kernel, and hopefully userland as well.
BFD_RELOC_32_PCREL_S2,
BFD_RELOC_16_PCREL_S2,
BFD_RELOC_23_PCREL_S2,
+ BFD_RELOC_18_PCREL_S2,
+ BFD_RELOC_28_PCREL_S2,
/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of
the target word. These are used on the SPARC. */
targ_defvec=m88kmach3_vec
targ_cflags=-DSTAT_FOR_EXEC
;;
- m88*-*-openbsd*)
- targ_defvec=m88kopenbsd_vec
- targ_underscore=yes
- ;;
+ m88k-*-openbsd*)
+ targ_defvec=bfd_elf32_m88k_vec
+ targ_selvecs="m88kopenbsd_vec m88kbcs_vec"
+ ;;
m88*-*-*)
targ_defvec=m88kbcs_vec
targ_underscore=yes
;;
vax-*-openbsd*)
- targ_defvec=elf32_vax_vec
+ targ_defvec=bfd_elf32_vax_vec
targ_selvecs=vaxnetbsd_vec
;;
-/* Motorola 88k-specific support for 32-bit ELF
- Copyright 1993, 1995, 1999 Free Software Foundation, Inc.
+/* Motorola 88k series support for 32-bit ELF
+ Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004, 2005, 2006 Free Software Foundation, Inc.
-This file is part of BFD, the Binary File Descriptor library.
+ This file is part of BFD, the Binary File Descriptor library.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#include "bfd.h"
#include "sysdep.h"
+#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
+#include "elf/m88k.h"
-/* This does not include any relocations, but should be good enough
- for GDB. */
+static reloc_howto_type *reloc_type_lookup (bfd *, bfd_reloc_code_real_type);
+static void rtype_to_howto (bfd *, arelent *, Elf_Internal_Rela *);
+static struct bfd_hash_entry *elf_m88k_link_hash_newfunc
+ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
+static struct bfd_link_hash_table *elf_m88k_link_hash_table_create (bfd *);
+static bfd_boolean elf_m88k_check_relocs
+ (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+static asection *elf_m88k_gc_mark_hook
+ (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *);
+static bfd_boolean elf_m88k_gc_sweep_hook
+ (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+static bfd_boolean elf_m88k_adjust_dynamic_symbol
+ (struct bfd_link_info *, struct elf_link_hash_entry *);
+static bfd_boolean elf_m88k_size_dynamic_sections
+ (bfd *, struct bfd_link_info *);
+static bfd_boolean elf_m88k_discard_copies
+ (struct elf_link_hash_entry *, PTR);
+static bfd_boolean elf_m88k_relocate_section
+ (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
+static bfd_boolean elf_m88k_finish_dynamic_symbol
+ (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *);
+static bfd_boolean elf_m88k_finish_dynamic_sections
+ (bfd *, struct bfd_link_info *);
-#define TARGET_BIG_SYM bfd_elf32_m88k_vec
-#define TARGET_BIG_NAME "elf32-m88k"
-#define ELF_ARCH bfd_arch_m88k
-#define ELF_MACHINE_CODE EM_88K
-#define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
-#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup
-#define elf_info_to_howto _bfd_elf_no_info_to_howto
+static bfd_boolean elf32_m88k_set_private_flags (bfd *, flagword);
+static bfd_boolean elf32_m88k_merge_private_bfd_data (bfd *, bfd *);
+static bfd_boolean elf32_m88k_print_private_bfd_data (bfd *, PTR);
+static enum elf_reloc_type_class elf32_m88k_reloc_type_class
+ (const Elf_Internal_Rela *);
+
+#define UNHANDLED_HOWTO(C) \
+ HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, __STRING(C), \
+ FALSE, 0, 0, FALSE)
+#define UNIMPLEMENTED_HOWTO \
+ HOWTO (R_88K_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \
+ "R_88K_UNIMPLEMENTED", FALSE, 0, 0, FALSE)
+
+static reloc_howto_type howto_table[] = {
+ HOWTO (R_88K_NONE, 0, 0, 0, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_NONE", FALSE, 0, 0x00000000,FALSE),
+ UNHANDLED_HOWTO (R_88K_COPY),
+ UNHANDLED_HOWTO (R_88K_GOTP_ENT),
+ UNIMPLEMENTED_HOWTO,
+ HOWTO (R_88K_8, 0, 0, 8, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_88K_8", FALSE, 0, 0x000000ff,FALSE),
+ UNHANDLED_HOWTO (R_88K_8S),
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_16S),
+ HOWTO (R_88K_DISP16, 2, 2,16, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_88K_DISP16", FALSE, 0, 0x0000ffff,TRUE),
+ UNIMPLEMENTED_HOWTO,
+ HOWTO (R_88K_DISP26, 2, 2,26, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_88K_DISP26", FALSE, 0, 0x03ffffff,TRUE),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ HOWTO (R_88K_PLT_DISP26, 2, 2,26, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_88K_PLT_DISP26", FALSE, 0, 0x03ffffff,TRUE),
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_BBASED_32),
+ UNHANDLED_HOWTO (R_88K_BBASED_32UA),
+ UNHANDLED_HOWTO (R_88K_BBASED_16H),
+ UNHANDLED_HOWTO (R_88K_BBASED_16L),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_ABDIFF_32),
+ UNHANDLED_HOWTO (R_88K_ABDIFF_32UA),
+ HOWTO (R_88K_ABDIFF_16H, 16, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_ABDIFF_16H", FALSE, 0, 0x0000ffff,FALSE),
+ HOWTO (R_88K_ABDIFF_16L, 0, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_ABDIFF_16L", FALSE, 0, 0x0000ffff,FALSE),
+ UNHANDLED_HOWTO (R_88K_ABDIFF_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ HOWTO (R_88K_32, 0, 2,32, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_88K_32", FALSE, 0, 0xffffffff,FALSE),
+ UNHANDLED_HOWTO (R_88K_32UA),
+ HOWTO (R_88K_16H, 16, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_16H", FALSE, 0, 0x0000ffff,FALSE),
+ HOWTO (R_88K_16L, 0, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_16L", FALSE, 0, 0x0000ffff,FALSE),
+ HOWTO (R_88K_16, 0, 1,16, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_88K_16", FALSE, 0, 0x0000ffff,FALSE),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_GOT_32),
+ UNHANDLED_HOWTO (R_88K_GOT_32UA),
+ HOWTO (R_88K_GOT_16H, 16, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_GOT_16H", FALSE, 0, 0x0000ffff,FALSE),
+ HOWTO (R_88K_GOT_16L, 0, 1,16, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_88K_GOT_16L", FALSE, 0, 0x0000ffff,FALSE),
+ UNHANDLED_HOWTO (R_88K_GOT_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_GOTP_32),
+ UNHANDLED_HOWTO (R_88K_GOTP_32UA),
+ UNHANDLED_HOWTO (R_88K_GOTP_16H),
+ UNHANDLED_HOWTO (R_88K_GOTP_16L),
+ UNHANDLED_HOWTO (R_88K_GOTP_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ HOWTO (R_88K_PLT_32, 0, 2,32, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_88K_PLT_32", FALSE, 0, 0xffffffff,FALSE),
+ UNHANDLED_HOWTO (R_88K_PLT_32UA),
+ UNHANDLED_HOWTO (R_88K_PLT_16H),
+ UNHANDLED_HOWTO (R_88K_PLT_16L),
+ UNHANDLED_HOWTO (R_88K_PLT_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_ABREL_32),
+ UNHANDLED_HOWTO (R_88K_ABREL_32UA),
+ UNHANDLED_HOWTO (R_88K_ABREL_16H),
+ UNHANDLED_HOWTO (R_88K_ABREL_16L),
+ UNHANDLED_HOWTO (R_88K_ABREL_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_GOT_ABREL_32),
+ UNHANDLED_HOWTO (R_88K_GOT_ABREL_32UA),
+ UNHANDLED_HOWTO (R_88K_GOT_ABREL_16H),
+ UNHANDLED_HOWTO (R_88K_GOT_ABREL_16L),
+ UNHANDLED_HOWTO (R_88K_GOT_ABREL_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_GOTP_ABREL_32),
+ UNHANDLED_HOWTO (R_88K_GOTP_ABREL_32UA),
+ UNHANDLED_HOWTO (R_88K_GOTP_ABREL_16H),
+ UNHANDLED_HOWTO (R_88K_GOTP_ABREL_16L),
+ UNHANDLED_HOWTO (R_88K_GOTP_ABREL_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_PLT_ABREL_32),
+ UNHANDLED_HOWTO (R_88K_PLT_ABREL_32UA),
+ UNHANDLED_HOWTO (R_88K_PLT_ABREL_16H),
+ UNHANDLED_HOWTO (R_88K_PLT_ABREL_16L),
+ UNHANDLED_HOWTO (R_88K_PLT_ABREL_16),
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNIMPLEMENTED_HOWTO,
+ UNHANDLED_HOWTO (R_88K_SREL_32),
+ UNHANDLED_HOWTO (R_88K_SREL_32UA),
+ UNHANDLED_HOWTO (R_88K_SREL_16H),
+ UNHANDLED_HOWTO (R_88K_SREL_16L),
+ /* GNU extension to record C++ vtable hierarchy */
+ HOWTO (R_88K_GNU_VTINHERIT,0,2,0, FALSE,0, complain_overflow_dont, NULL, "R_88K_GNU_VTINHERIT",FALSE,0,0, FALSE),
+ /* GNU extension to record C++ vtable member usage */
+ HOWTO (R_88K_GNU_VTENTRY,0, 2, 0, FALSE,0, complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_88K_GNU_VTENTRY",FALSE,0,0, FALSE)
+};
+
+static void
+rtype_to_howto (abfd, cache_ptr, dst)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr;
+ Elf_Internal_Rela *dst;
+{
+ BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_88K_UNIMPLEMENTED);
+ cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+#define elf_info_to_howto rtype_to_howto
+
+static const struct
+{
+ bfd_reloc_code_real_type bfd_val;
+ int elf_val;
+} reloc_map[] = {
+ { BFD_RELOC_NONE, R_88K_NONE },
+ { BFD_RELOC_LO16, R_88K_16L },
+ { BFD_RELOC_HI16, R_88K_16H },
+ { BFD_RELOC_18_PCREL_S2, R_88K_DISP16 },
+ { BFD_RELOC_28_PCREL_S2, R_88K_DISP26 },
+ { BFD_RELOC_8, R_88K_8 },
+ { BFD_RELOC_16, R_88K_16 },
+ { BFD_RELOC_32, R_88K_32 },
+
+ { BFD_RELOC_LO16_BASEREL, R_88K_ABDIFF_16L },
+ { BFD_RELOC_HI16_BASEREL, R_88K_ABDIFF_16H },
+ { BFD_RELOC_LO16_GOTOFF, R_88K_GOT_16L },
+ { BFD_RELOC_HI16_GOTOFF, R_88K_GOT_16H },
+ { BFD_RELOC_32_PLTOFF, R_88K_PLT_32 },
+ { BFD_RELOC_32_PLT_PCREL, R_88K_PLT_DISP26 },
+
+ { BFD_RELOC_VTABLE_INHERIT, R_88K_GNU_VTINHERIT },
+ { BFD_RELOC_VTABLE_ENTRY, R_88K_GNU_VTENTRY }
+};
+
+static reloc_howto_type *
+reloc_type_lookup (abfd, code)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
+{
+ unsigned int i;
+ for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++)
+ {
+ if (reloc_map[i].bfd_val == code)
+ return &howto_table[reloc_map[i].elf_val];
+ }
+ return 0;
+}
+
+#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup
+#define ELF_ARCH bfd_arch_m88k
+\f
+/* Functions for the m88k ELF linker. */
+
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
+
+/* The size in bytes of an entry in the procedure linkage table. */
+
+#define PLT_ENTRY_SIZE 24
+
+/* The size in bytes of the first entry in the procedure linkage table. */
+
+#define PLT_ENTRY0_SIZE (3 * PLT_ENTRY_SIZE)
+
+/* The first entry in a procedure linkage table looks like this. See
+ the SVR4 ABI m88k supplement to see how this works. */
+
+static const bfd_byte elf_m88k_plt0_entry[PLT_ENTRY0_SIZE] =
+{
+ 0x67, 0xff, 0x00, 0x10, /* subu r31, r31, 0x10 */
+ 0x24, 0x3f, 0x00, 0x0c, /* st r1, r31, 0x0c */
+ 0x25, 0x7f, 0x00, 0x08, /* st r11, r31, 0x08 */
+ 0xc8, 0x00, 0x00, 0x01, /* bsr 1f */
+ 0x5d, 0x60, 0x00, 0x00, /* 1: or.u r11, r0, %hi16(1b#abdiff) */
+ 0x59, 0x6b, 0x00, 0x00, /* or r11, r11, %lo16(1b#abdiff) */
+ 0xf5, 0x6b, 0x60, 0x01, /* addu r11, r11, r1 */
+ 0x14, 0x2b, 0x00, 0x04, /* ld r1, r11, 0x04 */
+ 0x24, 0x3f, 0x00, 0x04, /* st r1, r31, 0x04 */
+ 0x15, 0x6b, 0x00, 0x08, /* ld r11, r11, 0x08 */
+ 0x24, 0x1f, 0x00, 0x00, /* st r0, r31, 0 */
+ 0xf4, 0x00, 0xc8, 0x0b, /* jsr r11 */
+ 0xf4, 0x00, 0x58, 0x00, /* nop */
+ 0xf4, 0x00, 0x58, 0x00, /* nop */
+ 0xf4, 0x00, 0x58, 0x00, /* nop */
+ 0xf4, 0x00, 0x58, 0x00, /* nop */
+ 0xf4, 0x00, 0x58, 0x00, /* nop */
+ 0xf4, 0x00, 0x58, 0x00 /* nop */
+};
+
+/* Subsequent entries in a procedure linkage table look like this. */
+
+static const bfd_byte elf_m88k_plt_entry[PLT_ENTRY_SIZE] =
+{
+ 0x5d, 0x60, 0x00, 0x00, /* or.u r11, r0, %hi16(symbol#gotrel) */
+ 0x15, 0x6b, 0x00, 0x00, /* ld r11, r11, %lo16(symbol#gotrel) */
+ 0xf4, 0x00, 0xc0, 0x0b, /* jmp r11 */
+ 0x5d, 0x60, 0x00, 0x00, /* 1: or.u r11, r0, %hi16(.rela offset) */
+ 0x59, 0x6b, 0x00, 0x00, /* or r11, r11, %lo16(.rela offset) */
+ 0xc0, 0x00, 0x00, 0x00 /* br resolver */
+};
+
+/* The m88k linker needs to keep track of the number of relocs that it
+ decides to copy in check_relocs for each symbol. This is so that it
+ can discard PC relative relocs if it doesn't need them when linking
+ with -Bsymbolic. We store the information in a field extending the
+ regular ELF linker hash table. */
+
+/* This structure keeps track of the number of PC relative relocs we have
+ copied for a given symbol. */
+
+struct elf_m88k_pcrel_relocs_copied
+{
+ /* Next section. */
+ struct elf_m88k_pcrel_relocs_copied *next;
+ /* A section in dynobj. */
+ asection *section;
+ /* Number of relocs copied in this section. */
+ bfd_size_type count;
+};
+
+/* m88k ELF linker hash entry. */
+
+struct elf_m88k_link_hash_entry
+{
+ struct elf_link_hash_entry root;
+
+ /* Number of PC relative relocs copied for this symbol. */
+ struct elf_m88k_pcrel_relocs_copied *pcrel_relocs_copied;
+};
+
+#define elf_m88k_hash_entry(ent) ((struct elf_m88k_link_hash_entry *) (ent))
+
+/* m88k ELF linker hash table. */
+
+struct elf_m88k_link_hash_table
+{
+ struct elf_link_hash_table root;
+
+ /* Small local sym to section mapping cache. */
+ struct sym_sec_cache sym_sec;
+};
+
+/* Get the m88k ELF linker hash table from a link_info structure. */
+
+#define elf_m88k_hash_table(p) \
+ ((struct elf_m88k_link_hash_table *) (p)->hash)
+
+/* Create an entry in an m88k ELF linker hash table. */
+
+static struct bfd_hash_entry *
+elf_m88k_link_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct bfd_hash_entry *ret = entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == NULL)
+ ret = bfd_hash_allocate (table,
+ sizeof (struct elf_m88k_link_hash_entry));
+ if (ret == NULL)
+ return ret;
+
+ /* Call the allocation method of the superclass. */
+ ret = _bfd_elf_link_hash_newfunc (ret, table, string);
+ if (ret != NULL)
+ elf_m88k_hash_entry (ret)->pcrel_relocs_copied = NULL;
+
+ return ret;
+}
+
+/* Create an m88k ELF linker hash table. */
+
+static struct bfd_link_hash_table *
+elf_m88k_link_hash_table_create (abfd)
+ bfd *abfd;
+{
+ struct elf_m88k_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct elf_m88k_link_hash_table);
+
+ ret = (struct elf_m88k_link_hash_table *) bfd_alloc (abfd, amt);
+ if (ret == (struct elf_m88k_link_hash_table *) NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+ elf_m88k_link_hash_newfunc,
+ sizeof (struct elf_m88k_link_hash_entry)))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ ret->sym_sec.abfd = NULL;
+
+ return &ret->root.root;
+}
+
+/* Keep m88k-specific flags in the ELF header. */
+static bfd_boolean
+elf32_m88k_set_private_flags (abfd, flags)
+ bfd *abfd;
+ flagword flags;
+{
+ elf_elfheader (abfd)->e_flags = flags;
+ elf_flags_init (abfd) = TRUE;
+ return TRUE;
+}
+
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+static bfd_boolean
+elf32_m88k_merge_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ flagword out_flags;
+ flagword in_flags;
+
+ if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ in_flags = elf_elfheader (ibfd)->e_flags;
+ out_flags = elf_elfheader (obfd)->e_flags;
+
+ if (!elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = in_flags;
+ }
+
+ return TRUE;
+}
+
+/* Display the flags field. */
+static bfd_boolean
+elf32_m88k_print_private_bfd_data (abfd, ptr)
+ bfd *abfd;
+ PTR ptr;
+{
+ FILE *file = (FILE *) ptr;
+ flagword eflags;
+
+ BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+ /* Print normal ELF private data. */
+ _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+ eflags = elf_elfheader (abfd)->e_flags;
+
+ /* xgettext:c-format */
+ fprintf (file, _("private flags = %lx:"), (long) eflags);
+
+ if (eflags & EF_NABI)
+ fprintf (file, _(" [not ABI]"));
+
+ if (eflags & EF_M88110)
+ fprintf (file, _(" [m88110]"));
+
+ fputc ('\n', file);
+
+ return TRUE;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table or procedure linkage
+ table. */
+
+static bfd_boolean
+elf_m88k_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sgot;
+ asection *srelgot;
+ asection *sreloc;
+
+ if (info->relocatable)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ sgot = NULL;
+ srelgot = NULL;
+ sreloc = NULL;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ 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];
+ 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;
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_88K_GOT_16L:
+ case R_88K_GOT_16H:
+ /* This symbol requires a global offset table entry. */
+
+ if (dynobj == NULL)
+ {
+ /* Create the .got section. */
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (!_bfd_elf_create_got_section (dynobj, info))
+ return FALSE;
+ }
+
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+
+ if (srelgot == NULL
+ && (h != NULL || info->shared))
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_make_section_with_flags (dynobj,
+ ".rela.got",
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (srelgot == NULL
+ || !bfd_set_section_alignment (dynobj, srelgot, 2))
+ return FALSE;
+ }
+ }
+
+ if (h != NULL)
+ {
+ if (h->got.refcount == 0)
+ {
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ /* Allocate space in the .got section. */
+ sgot->size += 4;
+ /* Allocate relocation space. */
+ srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ h->got.refcount++;
+ }
+ else
+ {
+ /* This is a global offset table entry for a local symbol. */
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info;
+ size *= sizeof (bfd_signed_vma);
+ local_got_refcounts = ((bfd_signed_vma *)
+ bfd_zalloc (abfd, size));
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ }
+ if (local_got_refcounts[r_symndx] == 0)
+ {
+ sgot->size += 4;
+ if (info->shared)
+ {
+ /* If we are generating a shared object, we need to
+ output a R_88K_BBASED reloc so that the dynamic
+ linker can adjust this GOT entry. */
+ srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ }
+ local_got_refcounts[r_symndx]++;
+ }
+ break;
+
+ case R_88K_PLT_DISP26:
+ /* This symbol requires a procedure linkage table entry. We
+ actually build the entry in adjust_dynamic_symbol,
+ because this might be a case of linking PIC code which is
+ never referenced by a dynamic object, in which case we
+ don't need to generate a procedure linkage table entry
+ after all. */
+
+ /* If this is a local symbol, we resolve it directly without
+ creating a procedure linkage table entry. */
+ if (h == NULL)
+ continue;
+
+ h->needs_plt = 1;
+ h->plt.refcount++;
+ break;
+
+ case R_88K_PLT_32:
+ /* This symbol requires a procedure linkage table entry. */
+
+ if (h == NULL)
+ {
+ /* It does not make sense to have this relocation for a
+ local symbol. FIXME: does it? How to handle it if
+ it does make sense? */
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ h->needs_plt = 1;
+ h->plt.refcount++;
+ break;
+
+ case R_88K_DISP16:
+ case R_88K_DISP26:
+ /* If we are creating a shared library and this is not a local
+ symbol, we need to copy the reloc into the shared library.
+ However when linking with -Bsymbolic and this is a global
+ symbol which is defined in an object we are including in the
+ link (i.e., DEF_REGULAR is set), then we can resolve the
+ reloc directly. At this point we have not seen all the input
+ files, so it is possible that DEF_REGULAR is not set now but
+ will be set later (it is never cleared). We account for that
+ possibility below by storing information in the
+ pcrel_relocs_copied field of the hash table entry. */
+ if (!(info->shared
+ && (sec->flags & SEC_ALLOC) != 0
+ && h != NULL
+ && (!info->symbolic
+ || h->root.type == bfd_link_hash_defweak
+ || !h->def_regular)))
+ {
+ if (h != NULL)
+ {
+ /* Make sure a plt entry is created for this symbol if
+ it turns out to be a function defined by a dynamic
+ object. */
+ h->plt.refcount++;
+ }
+ break;
+ }
+ /* Fall through. */
+ case R_88K_32:
+ case R_88K_16L:
+ case R_88K_16H:
+ if (h != NULL)
+ {
+ /* Make sure a plt entry is created for this symbol if it
+ turns out to be a function defined by a dynamic object. */
+ h->plt.refcount++;
+ }
+
+ /* If we are creating a shared library, we need to copy the
+ reloc into the shared library. */
+ if (info->shared
+ && (sec->flags & SEC_ALLOC) != 0)
+ {
+ /* When creating a shared object, we must copy these
+ reloc types into the output file. We create a reloc
+ section in dynobj and make room for this reloc. */
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (abfd,
+ elf_elfheader (abfd)->e_shstrndx,
+ elf_section_data (sec)->rel_hdr.sh_name));
+ if (name == NULL)
+ return FALSE;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (abfd, sec),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ if (sreloc == NULL)
+ {
+ sreloc = bfd_make_section_with_flags (dynobj,
+ name,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (sreloc == NULL
+ || !bfd_set_section_alignment (dynobj, sreloc, 2))
+ return FALSE;
+ }
+ elf_section_data (sec)->sreloc = sreloc;
+ }
+
+ if (sec->flags & SEC_READONLY
+ /* Don't set DF_TEXTREL yet for PC relative
+ relocations, they might be discarded later. */
+ && !(ELF32_R_TYPE (rel->r_info) == R_88K_DISP16
+ || ELF32_R_TYPE (rel->r_info) == R_88K_DISP26))
+ info->flags |= DF_TEXTREL;
+
+ sreloc->size += sizeof (Elf32_External_Rela);
+
+ /* We count the number of PC relative relocations we have
+ entered for this symbol, so that we can discard them
+ again if, in the -Bsymbolic case, the symbol is later
+ defined by a regular object, or, in the normal shared
+ case, the symbol is forced to be local. Note that this
+ function is only called if we are using an m88kelf linker
+ hash table, which means that h is really a pointer to an
+ elf_m88k_link_hash_entry. */
+ if (ELF32_R_TYPE (rel->r_info) == R_88K_DISP16
+ || ELF32_R_TYPE (rel->r_info) == R_88K_DISP26)
+ {
+ struct elf_m88k_pcrel_relocs_copied *p;
+ struct elf_m88k_pcrel_relocs_copied **head;
+
+ if (h != NULL)
+ {
+ struct elf_m88k_link_hash_entry *eh
+ = elf_m88k_hash_entry (h);
+ head = &eh->pcrel_relocs_copied;
+ }
+ else
+ {
+ asection *s;
+ void *vpp;
+
+ s = (bfd_section_from_r_symndx
+ (abfd, &elf_m88k_hash_table (info)->sym_sec,
+ sec, r_symndx));
+ if (s == NULL)
+ return FALSE;
+
+ vpp = &elf_section_data (s)->local_dynrel;
+ head = (struct elf_m88k_pcrel_relocs_copied **) vpp;
+ }
+
+ for (p = *head; p != NULL; p = p->next)
+ if (p->section == sreloc)
+ break;
+
+ if (p == NULL)
+ {
+ p = ((struct elf_m88k_pcrel_relocs_copied *)
+ bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
+ if (p == NULL)
+ return FALSE;
+ p->next = *head;
+ *head = p;
+ p->section = sreloc;
+ p->count = 0;
+ }
+
+ ++p->count;
+ }
+ }
+
+ break;
+
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_88K_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_88K_GNU_VTENTRY:
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return FALSE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+elf_m88k_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_88K_GNU_VTINHERIT:
+ case R_88K_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ default:
+ break;
+
+ 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;
+ }
+ }
+ }
+ else
+ return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static bfd_boolean
+elf_m88k_gc_sweep_hook (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;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+ bfd *dynobj;
+ asection *sgot;
+ asection *srelgot;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj == NULL)
+ return TRUE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ {
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h = NULL;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ 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;
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_88K_GOT_16L:
+ case R_88K_GOT_16H:
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (h != NULL)
+ {
+ if (h->got.refcount > 0)
+ {
+ --h->got.refcount;
+ if (h->got.refcount == 0)
+ {
+ /* We don't need the .got entry any more. */
+ sgot->size -= 4;
+ srelgot->size -= sizeof (Elf32_External_Rela);
+ }
+ }
+ }
+ else if (local_got_refcounts != NULL)
+ {
+ if (local_got_refcounts[r_symndx] > 0)
+ {
+ --local_got_refcounts[r_symndx];
+ if (local_got_refcounts[r_symndx] == 0)
+ {
+ /* We don't need the .got entry any more. */
+ sgot->size -= 4;
+ if (info->shared)
+ srelgot->size -= sizeof (Elf32_External_Rela);
+ }
+ }
+ }
+ break;
+
+ case R_88K_PLT_DISP26:
+ case R_88K_PLT_32:
+ case R_88K_DISP16:
+ case R_88K_DISP26:
+ case R_88K_32:
+ case R_88K_16L:
+ case R_88K_16H:
+ if (h != NULL)
+ {
+ if (h->plt.refcount > 0)
+ --h->plt.refcount;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+static bfd_boolean
+elf_m88k_adjust_dynamic_symbol (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ bfd *dynobj;
+ asection *s;
+ unsigned int power_of_two;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ /* Make sure we know what is going on here. */
+ BFD_ASSERT (dynobj != NULL
+ && (h->needs_plt
+ || h->u.weakdef != NULL
+ || (h->def_dynamic
+ && h->ref_regular
+ && !h->def_regular)));
+
+ /* If this is a function, put it in the procedure linkage table. We
+ will fill in the contents of the procedure linkage table later,
+ when we know the address of the .got section. */
+ if (h->type == STT_FUNC
+ || h->needs_plt)
+ {
+ if ((h->plt.refcount <= 0
+ || SYMBOL_CALLS_LOCAL (info, h)
+ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak))
+ /* We must always create the plt entry if it was referenced
+ by a PLTxxO relocation. In this case we already recorded
+ it as a dynamic symbol. */
+ && h->dynindx == -1)
+ {
+ /* This case can occur if we saw a PLTxx reloc in an input
+ file, but the symbol was never referred to by a dynamic
+ object, or if all references were garbage collected. In
+ such a case, we don't actually need to build a procedure
+ linkage table, and we can just do a PCxx reloc instead. */
+ BFD_ASSERT (h->needs_plt);
+ h->plt.offset = (bfd_vma) -1;
+ h->needs_plt = 0;
+ return TRUE;
+ }
+
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ s = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (s != NULL);
+
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ if (s->size == 0)
+ {
+ s->size += PLT_ENTRY0_SIZE;
+ }
+
+ /* If this symbol is not defined in a regular file, and we are
+ not generating a shared library, then set the symbol to this
+ location in the .plt. This is required to make function
+ pointers compare as equal between the normal executable and
+ the shared library. */
+ if (!info->shared
+ && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->size;
+ }
+
+ h->plt.offset = s->size;
+
+ /* Make room for this entry. */
+ s->size += PLT_ENTRY_SIZE;
+
+ /* We also need to make an entry in the .got.plt section, which
+ will be placed in the .got section by the linker script. */
+ s = bfd_get_section_by_name (dynobj, ".got.plt");
+ BFD_ASSERT (s != NULL);
+ s->size += 4;
+
+ /* We also need to make an entry in the .rela.plt section. */
+ s = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (s != NULL);
+ s->size += sizeof (Elf32_External_Rela);
+
+ return TRUE;
+ }
+
+ /* Reinitialize the plt offset now that it is not used as a reference
+ count any more. */
+ h->plt.offset = (bfd_vma) -1;
+
+ /* 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;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. */
+
+ /* If we are creating a shared library, we must presume that the
+ only references to the symbol are via the global offset table.
+ For such cases we need not do anything here; the relocations will
+ be handled correctly by relocate_section. */
+ if (info->shared)
+ return TRUE;
+
+ if (h->size == 0)
+ {
+ (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+ h->root.root.string);
+ return TRUE;
+ }
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ s = bfd_get_section_by_name (dynobj, ".dynbss");
+ BFD_ASSERT (s != NULL);
+
+ /* We must generate a R_88K_COPY reloc to tell the dynamic linker to
+ copy the initial value out of the dynamic object and into the
+ runtime process image. We need to remember the offset into the
+ .rela.bss section we are going to use. */
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+ {
+ asection *srel;
+
+ srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+ BFD_ASSERT (srel != NULL);
+ srel->size += sizeof (Elf32_External_Rela);
+ h->needs_copy = 1;
+ }
+
+ /* We need to figure out the alignment required for this symbol. I
+ have no idea how other ELF linkers handle this. */
+ power_of_two = bfd_log2 (h->size);
+ if (power_of_two > 3)
+ power_of_two = 3;
+
+ /* Apply the required alignment. */
+ s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
+ if (power_of_two > bfd_get_section_alignment (dynobj, s))
+ {
+ if (!bfd_set_section_alignment (dynobj, s, power_of_two))
+ return FALSE;
+ }
+
+ /* Define the symbol as being at this point in the section. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->size;
+
+ /* Increment the section size to make room for the symbol. */
+ s->size += h->size;
+
+ return TRUE;
+}
+
+/* Set the sizes of the dynamic sections. */
+
+static bfd_boolean
+elf_m88k_size_dynamic_sections (output_bfd, info)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *s;
+ bfd_boolean plt;
+ bfd_boolean relocs;
+
+ 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 && !info->static_link)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+ }
+ else
+ {
+ /* We may have created entries in the .rela.got section.
+ However, if we are not creating the dynamic sections, we will
+ not actually use these entries. Reset the size of .rela.got,
+ which will cause it to get stripped from the output file
+ below. */
+ s = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (s != NULL)
+ s->size = 0;
+ }
+
+ /* If this is a -Bsymbolic shared link, then we need to discard all
+ PC relative relocs against symbols defined in a regular object.
+ For the normal shared case we discard the PC relative relocs
+ against symbols that have become local due to visibility changes.
+ We allocated space for them in the check_relocs routine, but we
+ will not fill them in in the relocate_section routine. */
+ if (info->shared)
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_m88k_discard_copies,
+ (PTR) info);
+
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ plt = FALSE;
+ relocs = FALSE;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ if (strcmp (name, ".plt") == 0)
+ {
+ /* Remember whether there is a PLT. */
+ plt = s->size != 0;
+ }
+ else if (strncmp (name, ".rela", 5) == 0)
+ {
+ if (s->size != 0)
+ {
+ relocs = TRUE;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ }
+ else if (strncmp (name, ".got", 4) != 0
+ && strncmp (name, ".dynbss", 4) != 0)
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (s->size == 0)
+ {
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ s->flags |= SEC_EXCLUDE;
+ continue;
+ }
+
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
+ /* Allocate memory for the section contents. */
+ /* FIXME: This should be a call to bfd_alloc not bfd_zalloc.
+ Unused entries should be reclaimed before the section's contents
+ are written out, but at the moment this does not happen. Thus in
+ order to prevent writing out garbage, we initialise the section's
+ contents to zero. */
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+ if (s->contents == NULL)
+ return FALSE;
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in elf_m88k_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+ if (!info->shared)
+ {
+ if (!add_dynamic_entry (DT_DEBUG, 0))
+ return FALSE;
+ }
+
+ if (plt)
+ {
+ if (!add_dynamic_entry (DT_PLTGOT, 0)
+ || !add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+ || !add_dynamic_entry (DT_JMPREL, 0)
+ || !add_dynamic_entry (DT_88K_PLTSTART, 0)
+ || !add_dynamic_entry (DT_88K_PLTEND, 0))
+ return FALSE;
+ }
+
+ if (relocs)
+ {
+ if (!add_dynamic_entry (DT_RELA, 0)
+ || !add_dynamic_entry (DT_RELASZ, 0)
+ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
+ return FALSE;
+ }
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return FALSE;
+ }
+ }
+#undef add_dynamic_entry
+
+ return TRUE;
+}
+
+/* This function is called via elf_link_hash_traverse if we are
+ creating a shared object. In the -Bsymbolic case it discards the
+ space allocated to copy PC relative relocs against symbols which
+ are defined in regular objects. For the normal shared case, it
+ discards space for pc-relative relocs that have become local due to
+ symbol visibility changes. We allocated space for them in the
+ check_relocs routine, but we won't fill them in in the
+ relocate_section routine.
+
+ We also check whether any of the remaining relocations apply
+ against a readonly section, and set the DF_TEXTREL flag in this
+ case. */
+
+static bfd_boolean
+elf_m88k_discard_copies (h, inf)
+ struct elf_link_hash_entry *h;
+ PTR inf;
+{
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct elf_m88k_pcrel_relocs_copied *s;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (!h->def_regular
+ || (!info->symbolic
+ && !h->forced_local))
+ {
+ if ((info->flags & DF_TEXTREL) == 0)
+ {
+ /* Look for relocations against read-only sections. */
+ for (s = elf_m88k_hash_entry (h)->pcrel_relocs_copied;
+ s != NULL;
+ s = s->next)
+ if ((s->section->flags & SEC_READONLY) != 0)
+ {
+ info->flags |= DF_TEXTREL;
+ break;
+ }
+ }
+
+ return TRUE;
+ }
+
+ for (s = elf_m88k_hash_entry (h)->pcrel_relocs_copied;
+ s != NULL;
+ s = s->next)
+ s->section->size -= s->count * sizeof (Elf32_External_Rela);
+
+ return TRUE;
+}
+
+/* Relocate an M88K ELF section. */
+
+static bfd_boolean
+elf_m88k_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections)
+ 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;
+{
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_vma *local_got_offsets;
+ asection *sgot;
+ asection *splt;
+ asection *sreloc;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+
+ if (info->relocatable)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ local_got_offsets = elf_local_got_offsets (input_bfd);
+
+ sgot = NULL;
+ splt = NULL;
+ sreloc = NULL;
+
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ int r_type;
+ const char *sym_name;
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ bfd_vma relocation;
+ bfd_boolean unresolved_reloc;
+ bfd_reloc_status_type r;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type < 0 || r_type >= (int) R_88K_UNIMPLEMENTED)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ howto = howto_table + r_type;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+ unresolved_reloc = FALSE;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+ }
+ else
+ {
+ bfd_boolean warned;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned);
+ }
+
+ if (h != NULL)
+ {
+ sym_name = h->root.root.string;
+ }
+ else
+ {
+ sym_name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ if (sym_name != NULL && *sym_name == '\0')
+ sym_name = bfd_section_name (input_bfd, sec);
+ }
+
+ switch (r_type)
+ {
+ case R_88K_GOT_16L:
+ case R_88K_GOT_16H:
+ /* Relocation is the offset of the entry for this symbol in
+ the global offset table. */
+ {
+ bfd_vma off;
+
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+
+ if (h != NULL)
+ {
+ bfd_boolean dyn;
+
+ off = h->got.offset;
+ BFD_ASSERT (off != (bfd_vma) -1);
+
+ dyn = elf_hash_table (info)->dynamic_sections_created;
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ || (info->shared
+ && (info->symbolic
+ || h->dynindx == -1
+ || h->forced_local)
+ && h->def_regular))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally, or the symbol was forced to be local
+ because of a version file.. We must initialize
+ this entry in the global offset table. Since
+ the offset must always be a multiple of 4, we
+ use the least significant bit to record whether
+ we have initialized it already.
+
+ When doing a dynamic link, we create a .rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ sgot->contents + off);
+ h->got.offset |= 1;
+ }
+ }
+ else
+ unresolved_reloc = FALSE;
+ }
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+ off = local_got_offsets[r_symndx];
+
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+ if (info->shared)
+ {
+ asection *s;
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ s = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (s != NULL);
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_info = ELF32_R_INFO (0, R_88K_BBASED_32);
+ outrel.r_addend = relocation;
+ loc = s->contents;
+ loc += s->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+
+ local_got_offsets[r_symndx] |= 1;
+ }
+ }
+
+ /* Addends on got relocations don't make much sense.
+ x+off@got is actually x@got+off, and since the got is
+ generated by a hash table traversal, the value in the
+ got at entry m+n bears little relation to the entry m. */
+ if (rel->r_addend != 0)
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): non-zero addend on %s reloc against `%s'"),
+ input_bfd, input_section, (long) rel->r_offset, howto->name,
+ sym_name);
+
+ relocation = sgot->output_offset + off;
+ }
+ break;
+
+ case R_88K_ABDIFF_16L:
+ case R_88K_ABDIFF_16H:
+ /* Relocation is the offset from this symbol to the address of
+ the global offset table. */
+
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+
+ relocation = sgot->output_section->vma
+ - (input_section->output_section->vma
+ + input_section->output_offset + rel->r_addend);
+ rel->r_addend = 0;
+ unresolved_reloc = FALSE;
+ break;
+
+ case R_88K_PLT_DISP26:
+ /* Relocation is to the entry for this symbol in the
+ procedure linkage table. */
+
+ /* Resolve a PLTxx reloc against a local symbol directly,
+ without using the procedure linkage table. */
+ if (h == NULL)
+ break;
+
+ if (h->plt.offset == (bfd_vma) -1
+ || !elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* We didn't make a PLT entry for this symbol. This
+ happens when statically linking PIC code, or when
+ using -Bsymbolic. */
+ break;
+ }
+
+ if (splt == NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL);
+ }
+
+ relocation = (splt->output_section->vma
+ + splt->output_offset
+ + h->plt.offset);
+ unresolved_reloc = FALSE;
+ break;
+
+ case R_88K_PLT_32:
+ /* Relocation is the offset of the entry for this symbol in
+ the procedure linkage table. */
+ BFD_ASSERT (h != NULL && h->plt.offset != (bfd_vma) -1);
+
+ if (splt == NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL);
+ }
+
+ relocation = h->plt.offset;
+ unresolved_reloc = FALSE;
+
+ /* This relocation does not use the addend. */
+ rel->r_addend = 0;
+
+ break;
+
+ case R_88K_DISP16:
+ case R_88K_DISP26:
+ if (h == NULL
+ || (info->shared
+ && h->forced_local))
+ break;
+ /* Fall through. */
+ case R_88K_8:
+ case R_88K_16:
+ case R_88K_32:
+ case R_88K_16L:
+ case R_88K_16H:
+ if (info->shared
+ && r_symndx != 0
+ && (input_section->flags & SEC_ALLOC) != 0
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && ((r_type != R_88K_DISP16
+ && r_type != R_88K_DISP26)
+ || (h != NULL
+ && h->dynindx != -1
+ && (!info->symbolic
+ || !h->def_regular))))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+ bfd_boolean skip, relocate;
+
+ /* When generating a shared object, these relocations
+ are copied into the output file to be resolved at run
+ time. */
+
+ skip = FALSE;
+ relocate = FALSE;
+
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset);
+ if (outrel.r_offset == (bfd_vma) -1)
+ skip = TRUE;
+ else if (outrel.r_offset == (bfd_vma) -2)
+ skip = TRUE, relocate = TRUE;
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+
+ if (skip)
+ memset (&outrel, 0, sizeof outrel);
+ else if (h != NULL
+ && h->dynindx != -1
+ && (r_type == R_88K_DISP16
+ || r_type == R_88K_DISP26
+ || !info->shared
+ || !info->symbolic
+ || !h->def_regular))
+ {
+ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ outrel.r_addend = rel->r_addend;
+ }
+ else
+ {
+ /* This symbol is local, or marked to become local. */
+ if (r_type == R_88K_32)
+ {
+ relocate = TRUE;
+ outrel.r_info = ELF32_R_INFO (0, R_88K_BBASED_32);
+ outrel.r_addend = relocation + rel->r_addend;
+ }
+ else
+ {
+ long indx;
+
+ if (bfd_is_abs_section (sec))
+ indx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ asection *osec;
+
+ osec = sec->output_section;
+ indx = elf_section_data (osec)->dynindx;
+ BFD_ASSERT (indx > 0);
+ }
+
+ outrel.r_info = ELF32_R_INFO (indx, r_type);
+ outrel.r_addend = relocation + rel->r_addend;
+ }
+ }
+
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL)
+ abort ();
+
+ loc = sreloc->contents;
+ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+
+ /* This reloc will be computed at runtime, so there's no
+ need to do anything now, except for R_88K_32
+ relocations that have been turned into
+ R_88K_BBASED_32. */
+ if (!relocate)
+ continue;
+ }
+
+ break;
+
+ case R_88K_GNU_VTINHERIT:
+ case R_88K_GNU_VTENTRY:
+ /* These are no-ops in the end. */
+ continue;
+
+ default:
+ break;
+ }
+
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
+ if (unresolved_reloc
+ && !((input_section->flags & SEC_DEBUGGING) != 0
+ && h->def_dynamic))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, (long) rel->r_offset, howto->name,
+ h->root.root.string);
+ return FALSE;
+ }
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+
+ if (r != bfd_reloc_ok)
+ {
+ if (sym_name == NULL)
+ return FALSE;
+
+ if (r == bfd_reloc_overflow)
+ {
+ if (!(info->callbacks->reloc_overflow
+ (info, (h ? &h->root : NULL), sym_name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section,
+ rel->r_offset)))
+ return FALSE;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): %s reloc against `%s': error %d"),
+ input_bfd, input_section, (long) rel->r_offset, howto->name,
+ sym_name, (int) r);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bfd_boolean
+elf_m88k_finish_dynamic_symbol (output_bfd, info, h, sym)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ bfd *dynobj;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ if (h->plt.offset != (bfd_vma) -1)
+ {
+ asection *splt;
+ asection *sgot;
+ asection *srela;
+ bfd_vma plt_index;
+ bfd_vma got_offset;
+ bfd_vma dyn_offset;
+ Elf_Internal_Rela rela;
+ unsigned int br;
+
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+ srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
+
+ /* Get the index in the procedure linkage table which
+ corresponds to this symbol. This is the index of this symbol
+ in all the symbols for which we are making plt entries. The
+ first entry in the procedure linkage table, spanning three
+ regular entries, is reserved. */
+ plt_index = (h->plt.offset - PLT_ENTRY0_SIZE) / PLT_ENTRY_SIZE;
+
+ /* Get the offset into the .got table of the entry that
+ corresponds to this function. Each .got entry is 4 bytes.
+ The first three are reserved. */
+ got_offset = (plt_index + 3) * 4;
+
+ /* Fill in the entry in the procedure linkage table. */
+ memcpy (splt->contents + h->plt.offset, elf_m88k_plt_entry,
+ PLT_ENTRY_SIZE);
+
+ dyn_offset = sgot->output_section->vma + sgot->output_offset + got_offset;
+ bfd_put_16 (output_bfd, dyn_offset >> 16,
+ splt->contents + h->plt.offset + 2);
+ bfd_put_16 (output_bfd, dyn_offset & 0xffff,
+ splt->contents + h->plt.offset + 6);
+
+ dyn_offset = plt_index * sizeof (Elf32_External_Rela);
+ bfd_put_16 (output_bfd, dyn_offset >> 16,
+ splt->contents + h->plt.offset + 14);
+ bfd_put_16 (output_bfd, dyn_offset & 0xffff,
+ splt->contents + h->plt.offset + 18);
+
+ br = bfd_get_32 (output_bfd, splt->contents + h->plt.offset + 20);
+ br &= ~0x03ffffff;
+ br |= 0x04000000 - ((h->plt.offset + 20) >> 2);
+ bfd_put_32 (output_bfd, br,
+ splt->contents + h->plt.offset + 20);
+
+ /* Fill in the entry in the global offset table. */
+ bfd_put_32 (output_bfd,
+ splt->output_section->vma
+ + splt->output_offset
+ + h->plt.offset
+ + 12,
+ sgot->contents + got_offset);
+
+ /* Fill in the entry in the .rela.plt section. */
+ rela.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + got_offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_88K_GOTP_ENT);
+ rela.r_addend = splt->output_section->vma + h->plt.offset;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ srela->contents
+ + plt_index * sizeof (Elf32_External_Rela));
+
+ if (!h->def_regular)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+ }
+
+ if (h->got.offset != (bfd_vma) -1)
+ {
+ asection *sgot;
+ asection *srela;
+ Elf_Internal_Rela rela;
+ bfd_byte *loc;
+
+ /* This symbol has an entry in the global offset table. Set it
+ up. */
+
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srela = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (sgot != NULL && srela != NULL);
+
+ rela.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + (h->got.offset &~ (bfd_vma) 1));
+
+ /* If this is a -Bsymbolic link, and the symbol is defined
+ locally, we just want to emit a BBASED reloc. Likewise if
+ the symbol was forced to be local because of a version file.
+ The entry in the global offset table will already have been
+ initialized in the relocate_section function. */
+ if (info->shared
+ && (info->symbolic
+ || h->dynindx == -1
+ || h->forced_local)
+ && h->def_regular)
+ {
+ rela.r_info = ELF32_R_INFO (0, R_88K_BBASED_32);
+ rela.r_addend = bfd_get_signed_32 (output_bfd,
+ (sgot->contents
+ + (h->got.offset &~ (bfd_vma) 1)));
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, (bfd_vma) 0,
+ sgot->contents + (h->got.offset &~ (bfd_vma) 1));
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_88K_32);
+ rela.r_addend = 0;
+ }
+
+ loc = srela->contents;
+ loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ }
+
+ if (h->needs_copy)
+ {
+ asection *s;
+ Elf_Internal_Rela rela;
+ bfd_byte *loc;
+
+ /* This symbol needs a copy reloc. Set it up. */
+
+ BFD_ASSERT (h->dynindx != -1
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak));
+
+ s = bfd_get_section_by_name (h->root.u.def.section->owner,
+ ".rela.bss");
+ BFD_ASSERT (s != NULL);
+
+ rela.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_88K_COPY);
+ rela.r_addend = 0;
+ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ }
+
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
+ if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || h == elf_hash_table (info)->hgot)
+ sym->st_shndx = SHN_ABS;
+
+ return TRUE;
+}
+
+/* Finish up the dynamic sections. */
+
+static bfd_boolean
+elf_m88k_finish_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *sgot;
+ asection *sdyn;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+ BFD_ASSERT (sgot != NULL);
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ asection *splt;
+ Elf32_External_Dyn *dyncon, *dynconend;
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+ dyncon = (Elf32_External_Dyn *) sdyn->contents;
+ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ asection *s;
+
+ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+ default:
+ break;
+
+ case DT_PLTGOT:
+ name = ".got";
+ goto get_vma;
+ case DT_JMPREL:
+ name = ".rela.plt";
+ get_vma:
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->vma;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
+ case DT_PLTRELSZ:
+ s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_val = s->size;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
+ case DT_RELASZ:
+ /* The procedure linkage table relocs (DT_JMPREL) should
+ not be included in the overall relocs (DT_RELA).
+ Therefore, we override the DT_RELASZ entry here to
+ make it not include the JMPREL relocs. Since the
+ linker script arranges for .rela.plt to follow all
+ other relocation sections, we don't have to worry
+ about changing the DT_RELA entry. */
+ s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+ if (s != NULL)
+ dyn.d_un.d_val -= s->size;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
+ case DT_88K_PLTSTART:
+ name = ".plt";
+ goto get_vma;
+ case DT_88K_PLTEND:
+ s = bfd_get_section_by_name (output_bfd, ".plt");
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->vma + s->size;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+ }
+ }
+
+ /* Fill in the first entry in the procedure linkage table. */
+ if (splt->size > 0)
+ {
+ memcpy (splt->contents, elf_m88k_plt0_entry, PLT_ENTRY0_SIZE);
+ bfd_put_16 (output_bfd,
+ (sgot->output_section->vma
+ + sgot->output_offset
+ - (splt->output_section->vma + 16)) >> 16,
+ splt->contents + 18);
+ bfd_put_16 (output_bfd,
+ (sgot->output_section->vma
+ + sgot->output_offset
+ - (splt->output_section->vma + 16)) & 0xffff,
+ splt->contents + 22);
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize
+ = PLT_ENTRY0_SIZE;
+ }
+ }
+
+ /* Fill in the first three entries in the global offset table. */
+ if (sgot->size > 0)
+ {
+ if (sdyn == NULL)
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+ else
+ bfd_put_32 (output_bfd,
+ sdyn->output_section->vma + sdyn->output_offset,
+ sgot->contents);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+ }
+
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+
+ return TRUE;
+}
+
+static enum elf_reloc_type_class
+elf32_m88k_reloc_type_class (rela)
+ const Elf_Internal_Rela *rela;
+{
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ case R_88K_BBASED_32:
+ case R_88K_BBASED_16H:
+ case R_88K_BBASED_16L:
+ return reloc_class_relative;
+ case R_88K_GOTP_ENT:
+ return reloc_class_plt;
+ case R_88K_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+static bfd_vma
+elf_m88k_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ return plt->vma + PLT_ENTRY0_SIZE + i * PLT_ENTRY_SIZE;
+}
+
+#define TARGET_BIG_SYM bfd_elf32_m88k_vec
+#define TARGET_BIG_NAME "elf32-m88k"
+#define ELF_MACHINE_CODE EM_88K
+#define ELF_MAXPAGESIZE 0x1000
+#define elf_backend_create_dynamic_sections \
+ _bfd_elf_create_dynamic_sections
+#define bfd_elf32_bfd_link_hash_table_create \
+ elf_m88k_link_hash_table_create
+#define bfd_elf32_bfd_final_link bfd_elf_gc_common_final_link
+
+#define elf_backend_check_relocs elf_m88k_check_relocs
+#define elf_backend_adjust_dynamic_symbol \
+ elf_m88k_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections \
+ elf_m88k_size_dynamic_sections
+#define elf_backend_relocate_section elf_m88k_relocate_section
+#define elf_backend_finish_dynamic_symbol \
+ elf_m88k_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+ elf_m88k_finish_dynamic_sections
+#define elf_backend_gc_mark_hook elf_m88k_gc_mark_hook
+#define elf_backend_gc_sweep_hook elf_m88k_gc_sweep_hook
+#define bfd_elf32_bfd_merge_private_bfd_data \
+ elf32_m88k_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags \
+ elf32_m88k_set_private_flags
+#define bfd_elf32_bfd_print_private_bfd_data \
+ elf32_m88k_print_private_bfd_data
+#define elf_backend_reloc_type_class elf32_m88k_reloc_type_class
+#define elf_backend_plt_sym_val elf_m88k_plt_sym_val
+
+#define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
+#define elf_backend_want_got_plt 1
+#define elf_backend_plt_readonly 1
+#define elf_backend_want_plt_sym 0
+#define elf_backend_got_header_size 12
+#define elf_backend_rela_normal 1
#include "elf32-target.h"
"BFD_RELOC_32_PCREL_S2",
"BFD_RELOC_16_PCREL_S2",
"BFD_RELOC_23_PCREL_S2",
+ "BFD_RELOC_18_PCREL_S2",
+ "BFD_RELOC_28_PCREL_S2",
"BFD_RELOC_HI22",
"BFD_RELOC_LO10",
"BFD_RELOC_GPREL16",
BFD_RELOC_16_PCREL_S2
ENUMX
BFD_RELOC_23_PCREL_S2
+ENUMX
+ BFD_RELOC_18_PCREL_S2
+ENUMX
+ BFD_RELOC_28_PCREL_S2
ENUMDOC
These PC-relative relocations are stored as word displacements --
i.e., byte displacements shifted right two bits. The 30-bit word
#include "elf/m32r.h"
#include "elf/m68k.h"
#include "elf/m68hc11.h"
+#include "elf/m88k.h"
#include "elf/mcore.h"
#include "elf/mips.h"
#include "elf/mmix.h"
case EM_BLACKFIN:
case EM_NIOS32:
case EM_ALTERA_NIOS2:
+ case EM_88K:
return TRUE;
case EM_MMA:
rtype = elf_bfin_reloc_type (type);
break;
+ case EM_88K:
+ rtype = elf_m88k_reloc_type (type);
+ break;
}
if (rtype == NULL)
if ((e_flags & EF_VAX_GFLOAT))
strcat (buf, ", G-Float");
break;
+
+ case EM_88K:
+ if ((e_flags & EF_NABI))
+ strcat (buf, ", not 88Open ABI compliant");
+ if ((e_flags & EF_M88110))
+ strcat (buf, ", m88110");
+ break;
}
}
M_29K = 101,
M_RS6000 = 102, /* IBM RS/6000 */
M_VAX4K_NETBSD = 150,
+ M_88K_OPENBSD = 153,
/* HP/BSD formats */
M_HP200 = 200, /* hp200 (68010) BSD binary */
M_HP300 = 300, /* hp300 (68020+68881) BSD binary */
--- /dev/null
+/* m88k-opcode.h -- Instruction information for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright 1989, 1990, 1991, 1993, 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 1, 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. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ Character codes for op_spec field below.
+ Reserved for self-matching: [ ] ,
+
+ d = GRF Destination register (21:5)
+ x = XRF register prefix. Makes next d, 1, or 2, match an extended register.
+ 1 = Source register 1 (16:5)
+ 2 = Source register 2 (0:5)
+ 3 = Both source registers (same value) (0:5 and 16:5)
+ I = IMM16 (0:16)
+ b = bit field spec. (0:10)
+ p = 16 bit pc displ. (0:16)
+ P = 26 bit pc displ. (0:26)
+ B = bb0/bb1 condition (21:5)
+ M = bcnd condition (21:5)
+ f = fcr (5:6)
+ c = cr (5:6)
+ V = VEC9 (0:9)
+ o = O6 field of "prot" insn (10:7)
+ ? = Give warning for this insn/operand combination
+ */
+
+/* instruction descriptor structure */
+
+struct m88k_opcode
+{
+ unsigned int opcode;
+ char *name;
+ char *op_spec;
+};
+
+/* and introducing... the Motorola 88100 and 88110 instruction sets... */
+
+/* By default, include the 88110 instructions. */
+#define MC88110
+
+#if defined (MC88110)
+#define _MC88100(OPCODE,MNEM,OP_SPEC)
+#define _MC88110(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC},
+#else
+#define _MC88100(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC},
+#define _MC88110(OPCODE,MNEM,OP_SPEC)
+#endif
+
+#define _MC88xxx(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC},
+
+/* Equal mnemonics must be adjacent.
+ More specific operand specification must go before more general.
+ For example, "d,1,2" must go before "d,1,I" as a register for s2
+ would otherwise be considered a variable name. */
+
+static struct m88k_opcode m88k_opcodes[] =
+{
+ /* Opcode Mnemonic Opspec */
+
+ _MC88xxx (0xf4007000, "add", "d,1,2")
+ _MC88xxx (0x70000000, "add", "d,1,I")
+ _MC88xxx (0xf4007200, "add.ci", "d,1,2")
+ _MC88xxx (0xf4007300, "add.cio", "d,1,2")
+ _MC88xxx (0xf4007100, "add.co", "d,1,2")
+ _MC88xxx (0xf4006000, "addu", "d,1,2")
+ _MC88xxx (0x60000000, "addu", "d,1,I")
+ _MC88xxx (0xf4006200, "addu.ci", "d,1,2")
+ _MC88xxx (0xf4006300, "addu.cio", "d,1,2")
+ _MC88xxx (0xf4006100, "addu.co", "d,1,2")
+ _MC88xxx (0xf4004000, "and", "d,1,2")
+ _MC88xxx (0x40000000, "and", "d,1,I")
+ _MC88xxx (0xf4004400, "and.c", "d,1,2")
+ _MC88xxx (0x44000000, "and.u", "d,1,I")
+ _MC88xxx (0xd0000000, "bb0", "B,1,p")
+ _MC88xxx (0xd4000000, "bb0.n", "B,1,p")
+ _MC88xxx (0xd8000000, "bb1", "B,1,p")
+ _MC88xxx (0xdc000000, "bb1.n", "B,1,p")
+ _MC88xxx (0xe8000000, "bcnd", "M,1,p")
+ _MC88xxx (0xec000000, "bcnd.n", "M,1,p")
+ _MC88xxx (0xc0000000, "br", "P")
+ _MC88xxx (0xc4000000, "br.n", "P")
+ _MC88xxx (0xc8000000, "bsr", "P")
+ _MC88xxx (0xcc000000, "bsr.n", "P")
+ _MC88xxx (0xf4008000, "clr", "d,1,2")
+ _MC88xxx (0xf0008000, "clr", "d,1,b")
+ _MC88xxx (0xf4007c00, "cmp", "d,1,2")
+ _MC88xxx (0x7c000000, "cmp", "d,1,I")
+ _MC88xxx (0xf4007800, "div", "d,1,2")
+ _MC88xxx (0x78000000, "div", "d,1,I")
+ _MC88xxx (0xf4007800, "divs", "d,1,2")
+ _MC88xxx (0x78000000, "divs", "d,1,I")
+ _MC88110 (0xf4006900, "divu.d", "d,1,2")
+ _MC88xxx (0xf4006800, "divu", "d,1,2")
+ _MC88xxx (0x68000000, "divu", "d,1,I")
+ _MC88xxx (0xf4009000, "ext", "d,1,2")
+ _MC88xxx (0xf0009000, "ext", "d,1,b")
+ _MC88xxx (0xf4009800, "extu", "d,1,2")
+ _MC88xxx (0xf0009800, "extu", "d,1,b")
+ _MC88xxx (0x84002800, "fadd.sss", "d,1,2")
+ _MC88110 (0x8400a800, "fadd.sss", "xd,x1,x2")
+ _MC88xxx (0x84002880, "fadd.ssd", "d,1,2")
+ _MC88110 (0x8400a820, "fadd.ssd", "xd,x1,x2")
+ _MC88110 (0x8400a840, "fadd.ssx", "xd,x1,x2")
+ _MC88xxx (0x84002a00, "fadd.sds", "d,1,2")
+ _MC88110 (0x8400a880, "fadd.sds", "xd,x1,x2")
+ _MC88xxx (0x84002a80, "fadd.sdd", "d,1,2")
+ _MC88110 (0x8400a8a0, "fadd.sdd", "xd,x1,x2")
+ _MC88110 (0x8400a8c0, "fadd.sdx", "xd,x1,x2")
+ _MC88110 (0x8400a900, "fadd.sxs", "xd,x1,x2")
+ _MC88110 (0x8400a920, "fadd.sxd", "xd,x1,x2")
+ _MC88110 (0x8400a940, "fadd.sxx", "xd,x1,x2")
+ _MC88xxx (0x84002820, "fadd.dss", "d,1,2")
+ _MC88110 (0x8400aa00, "fadd.dss", "xd,x1,x2")
+ _MC88xxx (0x840028a0, "fadd.dsd", "d,1,2")
+ _MC88110 (0x8400aa20, "fadd.dsd", "xd,x1,x2")
+ _MC88110 (0x8400aa40, "fadd.dsx", "xd,x1,x2")
+ _MC88xxx (0x84002a20, "fadd.dds", "d,1,2")
+ _MC88110 (0x8400aa80, "fadd.dds", "xd,x1,x2")
+ _MC88xxx (0x84002aa0, "fadd.ddd", "d,1,2")
+ _MC88110 (0x8400aaa0, "fadd.ddd", "xd,x1,x2")
+ _MC88110 (0x8400aac0, "fadd.ddx", "xd,x1,x2")
+ _MC88110 (0x8400ab00, "fadd.dxs", "xd,x1,x2")
+ _MC88110 (0x8400ab20, "fadd.dxd", "xd,x1,x2")
+ _MC88110 (0x8400ab40, "fadd.dxx", "xd,x1,x2")
+ _MC88110 (0x8400ac00, "fadd.xss", "xd,x1,x2")
+ _MC88110 (0x8400ac20, "fadd.xsd", "xd,x1,x2")
+ _MC88110 (0x8400ac40, "fadd.xsx", "xd,x1,x2")
+ _MC88110 (0x8400ac80, "fadd.xds", "xd,x1,x2")
+ _MC88110 (0x8400aca0, "fadd.xdd", "xd,x1,x2")
+ _MC88110 (0x8400acc0, "fadd.xdx", "xd,x1,x2")
+ _MC88110 (0x8400ad00, "fadd.xxs", "xd,x1,x2")
+ _MC88110 (0x8400ad20, "fadd.xxd", "xd,x1,x2")
+ _MC88110 (0x8400ad40, "fadd.xxx", "xd,x1,x2")
+ _MC88xxx (0x84003a80, "fcmp.sdd", "d,1,2")
+ _MC88110 (0x8400ba80, "fcmp.sdd", "d,x1,x2")
+ _MC88xxx (0x84003a00, "fcmp.sds", "d,1,2")
+ _MC88110 (0x8400ba00, "fcmp.sds", "d,x1,x2")
+ _MC88110 (0x8400bb00, "fcmp.sdx", "d,x1,x2")
+ _MC88xxx (0x84003880, "fcmp.ssd", "d,1,2")
+ _MC88110 (0x8400b880, "fcmp.ssd", "d,x1,x2")
+ _MC88xxx (0x84003800, "fcmp.sss", "d,1,2")
+ _MC88110 (0x8400b800, "fcmp.sss", "d,x1,x2")
+ _MC88110 (0x8400b900, "fcmp.ssx", "d,x1,x2")
+ _MC88110 (0x8400bc80, "fcmp.sxd", "d,x1,x2")
+ _MC88110 (0x8400bc00, "fcmp.sxs", "d,x1,x2")
+ _MC88110 (0x8400bd00, "fcmp.sxx", "d,x1,x2")
+ _MC88110 (0x84003aa0, "fcmpu.sdd", "d,1,2")
+ _MC88110 (0x8400baa0, "fcmpu.sdd", "d,x1,x2")
+ _MC88110 (0x84003a20, "fcmpu.sds", "d,1,2")
+ _MC88110 (0x8400ba20, "fcmpu.sds", "d,x1,x2")
+ _MC88110 (0x8400bb20, "fcmpu.sdx", "d,x1,x2")
+ _MC88110 (0x840038a0, "fcmpu.ssd", "d,1,2")
+ _MC88110 (0x8400b8a0, "fcmpu.ssd", "d,x1,x2")
+ _MC88110 (0x84003820, "fcmpu.sss", "d,1,2")
+ _MC88110 (0x8400b820, "fcmpu.sss", "d,x1,x2")
+ _MC88110 (0x8400b920, "fcmpu.ssx", "d,x1,x2")
+ _MC88110 (0x8400bca0, "fcmpu.sxd", "d,x1,x2")
+ _MC88110 (0x8400bc20, "fcmpu.sxs", "d,x1,x2")
+ _MC88110 (0x8400bd20, "fcmpu.sxx", "d,x1,x2")
+ _MC88110 (0x84000880, "fcvt.ds", "d,2")
+ _MC88110 (0x84008880, "fcvt.ds", "xd,x2")
+ _MC88110 (0x840088c0, "fcvt.dx", "xd,x2")
+ _MC88110 (0x84000820, "fcvt.sd", "d,2")
+ _MC88110 (0x84008820, "fcvt.sd", "xd,x2")
+ _MC88110 (0x84008840, "fcvt.sx", "xd,x2")
+ _MC88110 (0x84008920, "fcvt.xd", "xd,x2")
+ _MC88110 (0x84008900, "fcvt.xs", "xd,x2")
+ _MC88xxx (0x84007000, "fdiv.sss", "d,1,2")
+ _MC88110 (0x8400f000, "fdiv.sss", "xd,x1,x2")
+ _MC88xxx (0x84007080, "fdiv.ssd", "d,1,2")
+ _MC88110 (0x8400f020, "fdiv.ssd", "xd,x1,x2")
+ _MC88110 (0x8400f040, "fdiv.ssx", "xd,x1,x2")
+ _MC88xxx (0x84007200, "fdiv.sds", "d,1,2")
+ _MC88110 (0x8400f080, "fdiv.sds", "xd,x1,x2")
+ _MC88xxx (0x84007280, "fdiv.sdd", "d,1,2")
+ _MC88110 (0x8400f0a0, "fdiv.sdd", "xd,x1,x2")
+ _MC88110 (0x8400f0c0, "fdiv.sdx", "xd,x1,x2")
+ _MC88110 (0x8400f100, "fdiv.sxs", "xd,x1,x2")
+ _MC88110 (0x8400f120, "fdiv.sxd", "xd,x1,x2")
+ _MC88110 (0x8400f140, "fdiv.sxx", "xd,x1,x2")
+ _MC88xxx (0x84007020, "fdiv.dss", "d,1,2")
+ _MC88110 (0x8400f200, "fdiv.dss", "xd,x1,x2")
+ _MC88xxx (0x840070a0, "fdiv.dsd", "d,1,2")
+ _MC88110 (0x8400f220, "fdiv.dsd", "xd,x1,x2")
+ _MC88110 (0x8400f240, "fdiv.dsx", "xd,x1,x2")
+ _MC88xxx (0x84007220, "fdiv.dds", "d,1,2")
+ _MC88110 (0x8400f280, "fdiv.dds", "xd,x1,x2")
+ _MC88xxx (0x840072a0, "fdiv.ddd", "d,1,2")
+ _MC88110 (0x8400f2a0, "fdiv.ddd", "xd,x1,x2")
+ _MC88110 (0x8400f2c0, "fdiv.ddx", "xd,x1,x2")
+ _MC88110 (0x8400f300, "fdiv.dxs", "xd,x1,x2")
+ _MC88110 (0x8400f320, "fdiv.dxd", "xd,x1,x2")
+ _MC88110 (0x8400f340, "fdiv.dxx", "xd,x1,x2")
+ _MC88110 (0x8400f400, "fdiv.xss", "xd,x1,x2")
+ _MC88110 (0x8400f420, "fdiv.xsd", "xd,x1,x2")
+ _MC88110 (0x8400f440, "fdiv.xsx", "xd,x1,x2")
+ _MC88110 (0x8400f480, "fdiv.xds", "xd,x1,x2")
+ _MC88110 (0x8400f4a0, "fdiv.xdd", "xd,x1,x2")
+ _MC88110 (0x8400f4c0, "fdiv.xdx", "xd,x1,x2")
+ _MC88110 (0x8400f500, "fdiv.xxs", "xd,x1,x2")
+ _MC88110 (0x8400f520, "fdiv.xxd", "xd,x1,x2")
+ _MC88110 (0x8400f540, "fdiv.xxx", "xd,x1,x2")
+ _MC88xxx (0xf400ec00, "ff0", "d,2")
+ _MC88xxx (0xf400e800, "ff1", "d,2")
+ _MC88xxx (0x80004800, "fldcr", "d,f")
+ _MC88xxx (0x84002020, "flt.ds", "d,2")
+ _MC88110 (0x84002220, "flt.ds", "xd,2")
+ _MC88xxx (0x84002000, "flt.ss", "d,2")
+ _MC88110 (0x84002200, "flt.ss", "xd,2")
+ _MC88110 (0x84002240, "flt.xs", "xd,2")
+ _MC88xxx (0x84000000, "fmul.sss", "d,1,2")
+ _MC88110 (0x84008000, "fmul.sss", "xd,x1,x2")
+ _MC88xxx (0x84000080, "fmul.ssd", "d,1,2")
+ _MC88110 (0x84008020, "fmul.ssd", "xd,x1,x2")
+ _MC88110 (0x84008040, "fmul.ssx", "xd,x1,x2")
+ _MC88xxx (0x84000200, "fmul.sds", "d,1,2")
+ _MC88110 (0x84008080, "fmul.sds", "xd,x1,x2")
+ _MC88xxx (0x84000280, "fmul.sdd", "d,1,2")
+ _MC88110 (0x840080a0, "fmul.sdd", "xd,x1,x2")
+ _MC88110 (0x840080c0, "fmul.sdx", "xd,x1,x2")
+ _MC88110 (0x84008100, "fmul.sxs", "xd,x1,x2")
+ _MC88110 (0x84008120, "fmul.sxd", "xd,x1,x2")
+ _MC88110 (0x84008140, "fmul.sxx", "xd,x1,x2")
+ _MC88xxx (0x84000020, "fmul.dss", "d,1,2")
+ _MC88110 (0x84008200, "fmul.dss", "xd,x1,x2")
+ _MC88xxx (0x840000a0, "fmul.dsd", "d,1,2")
+ _MC88110 (0x84008220, "fmul.dsd", "xd,x1,x2")
+ _MC88110 (0x84008240, "fmul.dsx", "xd,x1,x2")
+ _MC88xxx (0x84000220, "fmul.dds", "d,1,2")
+ _MC88110 (0x84008280, "fmul.dds", "xd,x1,x2")
+ _MC88xxx (0x840002a0, "fmul.ddd", "d,1,2")
+ _MC88110 (0x840082a0, "fmul.ddd", "xd,x1,x2")
+ _MC88110 (0x840082c0, "fmul.ddx", "xd,x1,x2")
+ _MC88110 (0x84008300, "fmul.dxs", "xd,x1,x2")
+ _MC88110 (0x84008320, "fmul.dxd", "xd,x1,x2")
+ _MC88110 (0x84008340, "fmul.dxx", "xd,x1,x2")
+ _MC88110 (0x84008400, "fmul.xss", "xd,x1,x2")
+ _MC88110 (0x84008420, "fmul.xsd", "xd,x1,x2")
+ _MC88110 (0x84008440, "fmul.xsx", "xd,x1,x2")
+ _MC88110 (0x84008480, "fmul.xds", "xd,x1,x2")
+ _MC88110 (0x840084a0, "fmul.xdd", "xd,x1,x2")
+ _MC88110 (0x840084c0, "fmul.xdx", "xd,x1,x2")
+ _MC88110 (0x84008500, "fmul.xxs", "xd,x1,x2")
+ _MC88110 (0x84008520, "fmul.xxd", "xd,x1,x2")
+ _MC88110 (0x84008540, "fmul.xxx", "xd,x1,x2")
+ _MC88110 (0x840078a0, "fsqrt.dd", "d,2")
+ _MC88110 (0x8400f8a0, "fsqrt.dd", "xd,x2")
+ _MC88110 (0x84007880, "fsqrt.ds", "d,2")
+ _MC88110 (0x8400f880, "fsqrt.ds", "xd,x2")
+ _MC88110 (0x8400f8c0, "fsqrt.dx", "xd,x2")
+ _MC88110 (0x84007820, "fsqrt.sd", "d,2")
+ _MC88110 (0x8400f820, "fsqrt.sd", "xd,x2")
+ _MC88110 (0x84007800, "fsqrt.ss", "d,2")
+ _MC88110 (0x8400f800, "fsqrt.ss", "xd,x2")
+ _MC88110 (0x8400f840, "fsqrt.sx", "xd,x2")
+ _MC88110 (0x8400f920, "fsqrt.xd", "xd,x2")
+ _MC88110 (0x8400f900, "fsqrt.xs", "xd,x2")
+ _MC88110 (0x8400f940, "fsqrt.xx", "xd,x2")
+ _MC88xxx (0x80008800, "fstcr", "3,f")
+ _MC88xxx (0x84003000, "fsub.sss", "d,1,2")
+ _MC88110 (0x8400b000, "fsub.sss", "xd,x1,x2")
+ _MC88xxx (0x84003080, "fsub.ssd", "d,1,2")
+ _MC88110 (0x8400b020, "fsub.ssd", "xd,x1,x2")
+ _MC88110 (0x8400b040, "fsub.ssx", "xd,x1,x2")
+ _MC88xxx (0x84003200, "fsub.sds", "d,1,2")
+ _MC88110 (0x8400b080, "fsub.sds", "xd,x1,x2")
+ _MC88xxx (0x84003280, "fsub.sdd", "d,1,2")
+ _MC88110 (0x8400b0a0, "fsub.sdd", "xd,x1,x2")
+ _MC88110 (0x8400b0c0, "fsub.sdx", "xd,x1,x2")
+ _MC88110 (0x8400b100, "fsub.sxs", "xd,x1,x2")
+ _MC88110 (0x8400b120, "fsub.sxd", "xd,x1,x2")
+ _MC88110 (0x8400b140, "fsub.sxx", "xd,x1,x2")
+ _MC88xxx (0x84003020, "fsub.dss", "d,1,2")
+ _MC88110 (0x8400b200, "fsub.dss", "xd,x1,x2")
+ _MC88xxx (0x840030a0, "fsub.dsd", "d,1,2")
+ _MC88110 (0x8400b220, "fsub.dsd", "xd,x1,x2")
+ _MC88110 (0x8400b240, "fsub.dsx", "xd,x1,x2")
+ _MC88xxx (0x84003220, "fsub.dds", "d,1,2")
+ _MC88110 (0x8400b280, "fsub.dds", "xd,x1,x2")
+ _MC88xxx (0x840032a0, "fsub.ddd", "d,1,2")
+ _MC88110 (0x8400b2a0, "fsub.ddd", "xd,x1,x2")
+ _MC88110 (0x8400b2c0, "fsub.ddx", "xd,x1,x2")
+ _MC88110 (0x8400b300, "fsub.dxs", "xd,x1,x2")
+ _MC88110 (0x8400b320, "fsub.dxd", "xd,x1,x2")
+ _MC88110 (0x8400b340, "fsub.dxx", "xd,x1,x2")
+ _MC88110 (0x8400b400, "fsub.xss", "xd,x1,x2")
+ _MC88110 (0x8400b420, "fsub.xsd", "xd,x1,x2")
+ _MC88110 (0x8400b440, "fsub.xsx", "xd,x1,x2")
+ _MC88110 (0x8400b480, "fsub.xds", "xd,x1,x2")
+ _MC88110 (0x8400b4a0, "fsub.xdd", "xd,x1,x2")
+ _MC88110 (0x8400b4c0, "fsub.xdx", "xd,x1,x2")
+ _MC88110 (0x8400b500, "fsub.xxs", "xd,x1,x2")
+ _MC88110 (0x8400b520, "fsub.xxd", "xd,x1,x2")
+ _MC88110 (0x8400b540, "fsub.xxx", "xd,x1,x2")
+ _MC88xxx (0x8000c800, "fxcr", "d,3,f")
+ _MC88xxx (0x8400fc01, "illop1", "")
+ _MC88xxx (0x8400fc02, "illop2", "")
+ _MC88xxx (0x8400fc03, "illop3", "")
+ _MC88xxx (0x84004880, "int.sd", "d,2")
+ _MC88110 (0x8400c880, "int.sd", "d,x2")
+ _MC88xxx (0x84004800, "int.ss", "d,2")
+ _MC88110 (0x8400c800, "int.ss", "d,x2")
+ _MC88110 (0x8400c900, "int.sx", "d,x2")
+ _MC88xxx (0xf400c000, "jmp", "2")
+ _MC88xxx (0xf400c400, "jmp.n", "2")
+ _MC88xxx (0xf400c800, "jsr", "2")
+ _MC88xxx (0xf400cc00, "jsr.n", "2")
+ _MC88xxx (0xf4001400, "ld", "d,1,2")
+ _MC88xxx (0xf4001600, "ld", "d,1[2]")
+ _MC88xxx (0x14000000, "ld", "d,1,I")
+ _MC88110 (0xf0001600, "ld", "xd,1[2]")
+ _MC88110 (0xf0001400, "ld", "xd,1,2")
+ _MC88110 (0x04000000, "ld", "xd,1,I")
+ _MC88xxx (0xf4001e00, "ld.b", "d,1[2]")
+ _MC88xxx (0xf4001c00, "ld.b", "d,1,2")
+ _MC88xxx (0x1c000000, "ld.b", "d,1,I")
+ _MC88xxx (0xf4001d00, "ld.b.usr", "d,1,2")
+ _MC88xxx (0xf4001f00, "ld.b.usr", "d,1[2]")
+ _MC88xxx (0xf4000e00, "ld.bu", "d,1[2]")
+ _MC88xxx (0xf4000c00, "ld.bu", "d,1,2")
+ _MC88xxx (0x0c000000, "ld.bu", "d,1,I")
+ _MC88xxx (0xf4000d00, "ld.bu.usr", "d,1,2")
+ _MC88xxx (0xf4000f00, "ld.bu.usr", "d,1[2]")
+ _MC88xxx (0xf4001200, "ld.d", "d,1[2]")
+ _MC88xxx (0xf4001000, "ld.d", "d,1,2")
+ _MC88xxx (0x10000000, "ld.d", "d,1,I")
+ _MC88110 (0xf0001200, "ld.d", "xd,1[2]")
+ _MC88110 (0xf0001000, "ld.d", "xd,1,2")
+ _MC88110 (0x00000000, "ld.d", "xd,1,I")
+ _MC88xxx (0xf4001100, "ld.d.usr", "d,1,2")
+ _MC88xxx (0xf4001300, "ld.d.usr", "d,1[2]")
+ _MC88110 (0xf0001100, "ld.d.usr", "xd,1,2")
+ _MC88110 (0xf0001300, "ld.d.usr", "xd,1[2]")
+ _MC88xxx (0xf4001a00, "ld.h", "d,1[2]")
+ _MC88xxx (0xf4001800, "ld.h", "d,1,2")
+ _MC88xxx (0x18000000, "ld.h", "d,1,I")
+ _MC88xxx (0xf4001900, "ld.h.usr", "d,1,2")
+ _MC88xxx (0xf4001b00, "ld.h.usr", "d,1[2]")
+ _MC88xxx (0xf4000a00, "ld.hu", "d,1[2]")
+ _MC88xxx (0xf4000800, "ld.hu", "d,1,2")
+ _MC88xxx (0x08000000, "ld.hu", "d,1,I")
+ _MC88xxx (0xf4000900, "ld.hu.usr", "d,1,2")
+ _MC88xxx (0xf4000b00, "ld.hu.usr", "d,1[2]")
+ _MC88xxx (0xf4001500, "ld.usr", "d,1,2")
+ _MC88xxx (0xf4001700, "ld.usr", "d,1[2]")
+ _MC88110 (0xf0001500, "ld.usr", "xd,1,2")
+ _MC88110 (0xf0001700, "ld.usr", "xd,1[2]")
+ _MC88110 (0xf0001a00, "ld.x", "xd,1[2]")
+ _MC88110 (0xf0001800, "ld.x", "xd,1,2")
+ _MC88110 (0x3c000000, "ld.x", "xd,1,I")
+ _MC88110 (0xf0001900, "ld.x.usr", "xd,1,2")
+ _MC88110 (0xf0001b00, "ld.x.usr", "xd,1[2]")
+ _MC88xxx (0xf4003600, "lda", "d,1[2]")
+ _MC88xxx (0xf4006000, "lda", "?d,1,2") /* Output addu */
+ _MC88xxx (0x60000000, "lda", "?d,1,I") /* Output addu */
+ _MC88xxx (0xf4006000, "lda.b", "?d,1[2]") /* Output addu */
+ _MC88xxx (0xf4006000, "lda.b", "?d,1,2") /* Output addu */
+ _MC88xxx (0x60000000, "lda.b", "?d,1,I") /* Output addu */
+ _MC88xxx (0xf4003200, "lda.d", "d,1[2]")
+ _MC88xxx (0xf4006000, "lda.d", "?d,1,2") /* Output addu */
+ _MC88xxx (0x60000000, "lda.d", "?d,1,I") /* Output addu */
+ _MC88110 (0xf4003e00, "lda.x", "d,1[2]")
+ _MC88xxx (0xf4003a00, "lda.h", "d,1[2]")
+ _MC88xxx (0xf4006000, "lda.h", "?d,1,2") /* Output addu */
+ _MC88xxx (0x60000000, "lda.h", "?d,1,I") /* Output addu */
+ _MC88xxx (0x80004000, "ldcr", "d,c")
+ _MC88xxx (0xf400a000, "mak", "d,1,2")
+ _MC88xxx (0xf000a000, "mak", "d,1,b")
+ _MC88xxx (0x48000000, "mask", "d,1,I")
+ _MC88xxx (0x4c000000, "mask.u", "d,1,I")
+ _MC88110 (0x8400c000, "mov.s", "d,x2")
+ _MC88110 (0x84004200, "mov.s", "xd,2")
+ _MC88110 (0x8400c080, "mov.d", "d,x2")
+ _MC88110 (0x84004280, "mov.d", "xd,2")
+ _MC88110 (0x8400c300, "mov", "xd,x2")
+ _MC88xxx (0xf4006c00, "mul", "d,1,2")
+ _MC88xxx (0x6c000000, "mul", "d,1,I")
+ _MC88xxx (0xf4006e00, "muls", "d,1,2")
+ _MC88xxx (0x6c000000, "muls", "d,1,I")
+ _MC88xxx (0xf4006c00, "mulu", "d,1,2") /* synonym for mul */
+ _MC88xxx (0x6c000000, "mulu", "d,1,I") /* synonym for mul */
+ _MC88110 (0xf4006d00, "mulu.d", "d,1,2")
+ _MC88xxx (0x84005080, "nint.sd", "d,2")
+ _MC88110 (0x8400d080, "nint.sd", "d,x2")
+ _MC88xxx (0x84005000, "nint.ss", "d,2")
+ _MC88110 (0x8400d000, "nint.ss", "d,x2")
+ _MC88110 (0x8400d100, "nint.sx", "d,x2")
+ _MC88xxx (0xf4005800, "or", "d,1,2")
+ _MC88xxx (0x58000000, "or", "d,1,I")
+ _MC88xxx (0xf4005c00, "or.c", "d,1,2")
+ _MC88xxx (0x5c000000, "or.u", "d,1,I")
+ _MC88110 (0x88002020, "padd.b", "d,1,2")
+ _MC88110 (0x88002040, "padd.h", "d,1,2")
+ _MC88110 (0x88002060, "padd", "d,1,2")
+ _MC88110 (0x880020a0, "padds.u.b", "d,1,2")
+ _MC88110 (0x880020c0, "padds.u.h", "d,1,2")
+ _MC88110 (0x880020e0, "padds.u", "d,1,2")
+ _MC88110 (0x88002120, "padds.us.b", "d,1,2")
+ _MC88110 (0x88002140, "padds.us.h", "d,1,2")
+ _MC88110 (0x88002160, "padds.us", "d,1,2")
+ _MC88110 (0x880021a0, "padds.s.b", "d,1,2")
+ _MC88110 (0x880021c0, "padds.s.h", "d,1,2")
+ _MC88110 (0x880021e0, "padds.s", "d,1,2")
+ _MC88110 (0x88003860, "pcmp", "d,1,2")
+ _MC88110 (0x88000000, "pmul", "d,1,2")
+ _MC88110 (0x88006420, "ppack.32.b", "d,1,2")
+ _MC88110 (0x88006240, "ppack.16.h", "d,1,2")
+ _MC88110 (0x88006440, "ppack.32.h", "d,1,2")
+ _MC88110 (0x88006160, "ppack.8", "d,1,2")
+ _MC88110 (0x88006260, "ppack.16", "d,1,2")
+ _MC88110 (0x88006460, "ppack.32", "d,1,2")
+ _MC88110 (0x88007800, "prot", "d,1,2")
+ _MC88110 (0x88007000, "prot", "d,1,o")
+ _MC88110 (0x88003020, "psub.b", "d,1,2")
+ _MC88110 (0x88003040, "psub.h", "d,1,2")
+ _MC88110 (0x88003060, "psub", "d,1,2")
+ _MC88110 (0x880030a0, "psubs.u.b", "d,1,2")
+ _MC88110 (0x880030c0, "psubs.u.h", "d,1,2")
+ _MC88110 (0x880030e0, "psubs.u", "d,1,2")
+ _MC88110 (0x88003120, "psubs.us.b", "d,1,2")
+ _MC88110 (0x88003140, "psubs.us.h", "d,1,2")
+ _MC88110 (0x88003160, "psubs.us", "d,1,2")
+ _MC88110 (0x880031a0, "psubs.s.b", "d,1,2")
+ _MC88110 (0x880031c0, "psubs.s.h", "d,1,2")
+ _MC88110 (0x880031e0, "psubs.s", "d,1,2")
+ _MC88110 (0x88006800, "punpk.n", "d,1")
+ _MC88110 (0x88006820, "punpk.b", "d,1")
+ _MC88110 (0x88006840, "punpk.h", "d,1")
+ _MC88xxx (0xf400a800, "rot", "d,1,2")
+ _MC88xxx (0xf000a800, "rot", "d,1,b")
+ _MC88xxx (0xf400fc00, "rte", "")
+ _MC88xxx (0xf4008800, "set", "d,1,2")
+ _MC88xxx (0xf0008800, "set", "d,1,b")
+ _MC88xxx (0xf4002600, "st", "d,1[2]")
+ _MC88xxx (0xf4002400, "st", "d,1,2")
+ _MC88xxx (0x24000000, "st", "d,1,I")
+ _MC88110 (0xf0002600, "st", "xd,1[2]")
+ _MC88110 (0xf0002400, "st", "xd,1,2")
+ _MC88110 (0x34000000, "st", "xd,1,I")
+ _MC88xxx (0xf4002e00, "st.b", "d,1[2]")
+ _MC88xxx (0xf4002c00, "st.b", "d,1,2")
+ _MC88xxx (0x2c000000, "st.b", "d,1,I")
+ _MC88xxx (0xf4002d00, "st.b.usr", "d,1,2")
+ _MC88xxx (0xf4002f00, "st.b.usr", "d,1[2]")
+ _MC88110 (0xf4002d80, "st.b.usr.wt", "d,1,2")
+ _MC88110 (0xf4002f80, "st.b.usr.wt", "d,1[2]")
+ _MC88110 (0xf4002c80, "st.b.wt", "d,1,2")
+ _MC88110 (0xf4002e80, "st.b.wt", "d,1[2]")
+ _MC88xxx (0xf4002200, "st.d", "d,1[2]")
+ _MC88xxx (0xf4002000, "st.d", "d,1,2")
+ _MC88xxx (0x20000000, "st.d", "d,1,I")
+ _MC88110 (0xf0002200, "st.d", "xd,1[2]")
+ _MC88110 (0xf0002000, "st.d", "xd,1,2")
+ _MC88110 (0x30000000, "st.d", "xd,1,I")
+ _MC88xxx (0xf4002100, "st.d.usr", "d,1,2")
+ _MC88xxx (0xf4002300, "st.d.usr", "d,1[2]")
+ _MC88110 (0xf0002100, "st.d.usr", "xd,1,2")
+ _MC88110 (0xf0002300, "st.d.usr", "xd,1[2]")
+ _MC88110 (0xf4002180, "st.d.usr.wt", "d,1,2")
+ _MC88110 (0xf4002380, "st.d.usr.wt", "d,1[2]")
+ _MC88110 (0xf0002180, "st.d.usr.wt", "xd,1,2")
+ _MC88110 (0xf0002380, "st.d.usr.wt", "xd,1[2]")
+ _MC88110 (0xf4002080, "st.d.wt", "d,1,2")
+ _MC88110 (0xf4002280, "st.d.wt", "d,1[2]")
+ _MC88110 (0xf0002080, "st.d.wt", "xd,1,2")
+ _MC88110 (0xf0002280, "st.d.wt", "xd,1[2]")
+ _MC88xxx (0xf4002a00, "st.h", "d,1[2]")
+ _MC88xxx (0xf4002800, "st.h", "d,1,2")
+ _MC88xxx (0x28000000, "st.h", "d,1,I")
+ _MC88xxx (0xf4002900, "st.h.usr", "d,1,2")
+ _MC88xxx (0xf4002b00, "st.h.usr", "d,1[2]")
+ _MC88110 (0xf4002980, "st.h.usr.wt", "d,1,2")
+ _MC88110 (0xf4002b80, "st.h.usr.wt", "d,1[2]")
+ _MC88110 (0xf4002880, "st.h.wt", "d,1,2")
+ _MC88110 (0xf4002a80, "st.h.wt", "d,1[2]")
+ _MC88xxx (0xf4002500, "st.usr", "d,1,2")
+ _MC88xxx (0xf4002700, "st.usr", "d,1[2]")
+ _MC88110 (0xf0002500, "st.usr", "xd,1,2")
+ _MC88110 (0xf0002700, "st.usr", "xd,1[2]")
+ _MC88110 (0xf4002580, "st.usr.wt", "d,1,2")
+ _MC88110 (0xf4002780, "st.usr.wt", "d,1[2]")
+ _MC88110 (0xf0002580, "st.usr.wt", "xd,1,2")
+ _MC88110 (0xf0002780, "st.usr.wt", "xd,1[2]")
+ _MC88110 (0xf4002480, "st.wt", "d,1,2")
+ _MC88110 (0xf4002680, "st.wt", "d,1[2]")
+ _MC88110 (0xf0002480, "st.wt", "xd,1,2")
+ _MC88110 (0xf0002680, "st.wt", "xd,1[2]")
+ _MC88110 (0xf0002a00, "st.x", "xd,1[2]")
+ _MC88110 (0xf0002800, "st.x", "xd,1,2")
+ _MC88110 (0x38000000, "st.x", "xd,1,I")
+ _MC88110 (0xf0002900, "st.x.usr", "xd,1,2")
+ _MC88110 (0xf0002b00, "st.x.usr", "xd,1[2]")
+ _MC88110 (0xf0002980, "st.x.usr.wt", "xd,1,2")
+ _MC88110 (0xf0002b80, "st.x.usr.wt", "xd,1[2]")
+ _MC88110 (0xf0002880, "st.x.wt", "xd,1,2")
+ _MC88110 (0xf0002a80, "st.x.wt", "xd,1[2]")
+ _MC88xxx (0x80008000, "stcr", "3,c")
+ _MC88xxx (0xf4007400, "sub", "d,1,2")
+ _MC88xxx (0x74000000, "sub", "d,1,I")
+ _MC88xxx (0xf4007600, "sub.ci", "d,1,2")
+ _MC88xxx (0xf4007700, "sub.cio", "d,1,2")
+ _MC88xxx (0xf4007500, "sub.co", "d,1,2")
+ _MC88xxx (0xf4006400, "subu", "d,1,2")
+ _MC88xxx (0x64000000, "subu", "d,1,I")
+ _MC88xxx (0xf4006600, "subu.ci", "d,1,2")
+ _MC88xxx (0xf4006700, "subu.cio", "d,1,2")
+ _MC88xxx (0xf4006500, "subu.co", "d,1,2")
+ _MC88xxx (0xf000d000, "tb0", "B,1,V")
+ _MC88xxx (0xf000d800, "tb1", "B,1,V")
+ _MC88xxx (0xf400f800, "tbnd", "1,2")
+ _MC88xxx (0xf8000000, "tbnd", "1,I")
+ _MC88xxx (0xf000e800, "tcnd", "M,1,V")
+ _MC88xxx (0x84005880, "trnc.sd", "d,2")
+ _MC88110 (0x8400d880, "trnc.sd", "d,x2")
+ _MC88xxx (0x84005800, "trnc.ss", "d,2")
+ _MC88110 (0x8400d800, "trnc.ss", "d,x2")
+ _MC88110 (0x8400d900, "trnc.sx", "d,x2")
+ _MC88xxx (0x8000c000, "xcr", "d,3,c")
+ _MC88xxx (0xf4000600, "xmem", "d,1[2]")
+ _MC88xxx (0xf4000400, "xmem", "d,1,2")
+ _MC88100 (0x04000000, "xmem", "?d,1,I")
+ _MC88xxx (0xf4000200, "xmem.bu", "d,1[2]")
+ _MC88xxx (0xf4000000, "xmem.bu", "d,1,2")
+ _MC88100 (0x00000000, "xmem.bu", "?d,1,I")
+ _MC88xxx (0xf4000300, "xmem.bu.usr", "d,1[2]")
+ _MC88xxx (0xf4000100, "xmem.bu.usr", "d,1,2")
+ _MC88100 (0x00000100, "xmem.bu.usr", "?d,1,I")
+ _MC88xxx (0xf4000700, "xmem.usr", "d,1[2]")
+ _MC88xxx (0xf4000500, "xmem.usr", "d,1,2")
+ _MC88100 (0x04000100, "xmem.usr", "?d,1,I")
+ _MC88xxx (0xf4005000, "xor", "d,1,2")
+ _MC88xxx (0x50000000, "xor", "d,1,I")
+ _MC88xxx (0xf4005400, "xor.c", "d,1,2")
+ _MC88xxx (0x54000000, "xor.u", "d,1,I")
+ _MC88xxx (0x00000000, "", 0)
+};
+
+#define NUMOPCODES ((sizeof m88k_opcodes)/(sizeof m88k_opcodes[0]))
--- /dev/null
+/* m88k.c -- Assembler for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999,
+ 2000, 2001, 2002
+ 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. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "m88k-opcode.h"
+
+#if defined (OBJ_ELF)
+#include "elf/m88k.h"
+#endif
+
+#define RELOC_LO16 BFD_RELOC_LO16
+#define RELOC_HI16 BFD_RELOC_HI16
+#define RELOC_PC16 BFD_RELOC_18_PCREL_S2
+#define RELOC_PC26 BFD_RELOC_28_PCREL_S2
+#define RELOC_32 BFD_RELOC_32
+#define NO_RELOC BFD_RELOC_NONE
+
+struct field_val_assoc
+{
+ char *name;
+ unsigned val;
+};
+
+struct field_val_assoc m88100_cr_regs[] =
+{
+ {"PID", 0},
+ {"PSR", 1},
+ {"EPSR", 2},
+ {"SSBR", 3},
+ {"SXIP", 4},
+ {"SNIP", 5},
+ {"SFIP", 6},
+ {"VBR", 7},
+ {"DMT0", 8},
+ {"DMD0", 9},
+ {"DMA0", 10},
+ {"DMT1", 11},
+ {"DMD1", 12},
+ {"DMA1", 13},
+ {"DMT2", 14},
+ {"DMD2", 15},
+ {"DMA2", 16},
+ {"SR0", 17},
+ {"SR1", 18},
+ {"SR2", 19},
+ {"SR3", 20},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc m88110_cr_regs[] =
+{
+ {"PID", 0},
+ {"PSR", 1},
+ {"EPSR", 2},
+ {"EXIP", 4},
+ {"ENIP", 5},
+ {"VBR", 7},
+ {"SRX", 16},
+ {"SR0", 17},
+ {"SR1", 18},
+ {"SR2", 19},
+ {"SR3", 20},
+ {"ICMD", 25},
+ {"ICTL", 26},
+ {"ISAR", 27},
+ {"ISAP", 28},
+ {"IUAP", 29},
+ {"IIR", 30},
+ {"IBP", 31},
+ {"IPPU", 32},
+ {"IPPL", 33},
+ {"ISR", 34},
+ {"ILAR", 35},
+ {"IPAR", 36},
+ {"DCMD", 40},
+ {"DCTL", 41},
+ {"DSAR", 42},
+ {"DSAP", 43},
+ {"DUAP", 44},
+ {"DIR", 45},
+ {"DBP", 46},
+ {"DPPU", 47},
+ {"DPPL", 48},
+ {"DSR", 49},
+ {"DLAR", 50},
+ {"DPAR", 51},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc fcr_regs[] =
+{
+ {"FPECR", 0},
+ {"FPHS1", 1},
+ {"FPLS1", 2},
+ {"FPHS2", 3},
+ {"FPLS2", 4},
+ {"FPPT", 5},
+ {"FPRH", 6},
+ {"FPRL", 7},
+ {"FPIT", 8},
+
+ {"FPSR", 62},
+ {"FPCR", 63},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc cmpslot[] =
+{
+/* Integer Floating point */
+ {"nc", 0},
+ {"cp", 1},
+ {"eq", 2},
+ {"ne", 3},
+ {"gt", 4},
+ {"le", 5},
+ {"lt", 6},
+ {"ge", 7},
+ {"hi", 8}, {"ou", 8},
+ {"ls", 9}, {"ib", 9},
+ {"lo", 10}, {"in", 10},
+ {"hs", 11}, {"ob", 11},
+ {"be", 12}, {"ue", 12},
+ {"nb", 13}, {"lg", 13},
+ {"he", 14}, {"ug", 14},
+ {"nh", 15}, {"ule", 15},
+ {"ul", 16},
+ {"uge", 17},
+
+ {NULL, 0},
+};
+
+struct field_val_assoc cndmsk[] =
+{
+ {"gt0", 1},
+ {"eq0", 2},
+ {"ge0", 3},
+ {"lt0", 12},
+ {"ne0", 13},
+ {"le0", 14},
+
+ {NULL, 0},
+};
+
+struct m88k_insn
+{
+ unsigned long opcode;
+ expressionS exp;
+ enum m88k_reloc_type reloc;
+};
+
+static char *get_bf (char *param, unsigned *valp);
+static char *get_cmp (char *param, unsigned *valp);
+static char *get_cnd (char *param, unsigned *valp);
+static char *get_bf2 (char *param, int bc);
+static char *get_bf_offset_expression (char *param, unsigned *offsetp);
+static char *get_cr (char *param, unsigned *regnop);
+static char *get_fcr (char *param, unsigned *regnop);
+static char *get_imm16 (char *param, struct m88k_insn *insn);
+static char *get_o6 (char *param, unsigned *valp);
+static char *match_name (char *, struct field_val_assoc *, unsigned *);
+static char *get_reg (char *param, unsigned *regnop, unsigned int reg_prefix);
+static char *get_vec9 (char *param, unsigned *valp);
+static char *getval (char *param, unsigned int *valp);
+static char *get_pcr (char *param, struct m88k_insn *insn,
+ enum m88k_reloc_type reloc);
+
+static int calcop (struct m88k_opcode *format,
+ char *param, struct m88k_insn *insn);
+
+static void s_m88k_88110 (int);
+
+static struct hash_control *op_hash = NULL;
+
+/* Current cpu (either 88100 or 88110, or 0 if unspecified). Defaults to
+ zero, overriden with -m<cpu> options or assembler pseudo-ops. */
+static int current_cpu = 0;
+
+/* These chars start a comment anywhere in a source file (except inside
+ another comment. */
+#if defined(OBJ_ELF)
+const char comment_chars[] = "|";
+#elif defined(OBJ_AOUT)
+const char comment_chars[] = "|#";
+#else
+const char comment_chars[] = ";";
+#endif
+
+/* These chars only start a comment at the beginning of a line. */
+#if defined(OBJ_AOUT)
+const char line_comment_chars[] = ";";
+#else
+const char line_comment_chars[] = "#";
+#endif
+
+#if defined(OBJ_ELF)
+const char line_separator_chars[] = ";";
+#else
+const char line_separator_chars[] = "";
+#endif
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* as in 0f123.456 */
+/* or 0H1.234E-12 (see exp chars above) */
+const char FLT_CHARS[] = "dDfF";
+
+const pseudo_typeS md_pseudo_table[] =
+{
+#ifndef OBJ_ELF
+ {"align", s_align_bytes, 4},
+#else
+ /* handled with s_align_ptwo in read.c potable[] */
+#endif
+ {"bss", s_lcomm, 1},
+ {"def", s_set, 0},
+ {"half", cons, 2},
+ {"requires_88110", s_m88k_88110, 0},
+ {"sbss", s_lcomm, 1},
+#if !defined(OBJ_ELF) || !defined(TE_OpenBSD) /* i.e. NO_PSEUDO_DOT == 1 */
+ /* Force set to be treated as an instruction. */
+ {"set", NULL, 0},
+ {".set", s_set, 0},
+#endif
+ {"uahalf", cons, 2},
+ {"uaword", cons, 4},
+ {"word", cons, 4}, /* override potable[] which has word == short */
+ {NULL, NULL, 0}
+};
+
+static void
+s_m88k_88110(int i ATTRIBUTE_UNUSED)
+{
+ current_cpu = 88110;
+}
+
+void
+md_begin (void)
+{
+ const char *retval = NULL;
+ unsigned int i = 0;
+
+ /* Initialize hash table. */
+ op_hash = hash_new ();
+
+ while (*m88k_opcodes[i].name)
+ {
+ char *name = m88k_opcodes[i].name;
+
+ /* Hash each mnemonic and record its position. */
+ retval = hash_insert (op_hash, name, &m88k_opcodes[i]);
+
+ if (retval != NULL)
+ as_fatal (_("Can't hash instruction '%s':%s"),
+ m88k_opcodes[i].name, retval);
+
+ /* Skip to next unique mnemonic or end of list. */
+ for (i++; !strcmp (m88k_opcodes[i].name, name); i++)
+ ;
+ }
+
+#ifdef OBJ_ELF
+ record_alignment (text_section, 2);
+ record_alignment (data_section, 2);
+ record_alignment (bss_section, 2);
+
+ bfd_set_private_flags (stdoutput, 0);
+#endif
+}
+\f
+const char *md_shortopts = "m:";
+struct option md_longopts[] = {
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+int
+md_parse_option (int c, char *arg)
+{
+ switch (c)
+ {
+ case 'm':
+ if (strcmp (arg, "88100") == 0)
+ current_cpu = 88100;
+ else if (strcmp (arg, "88110") == 0)
+ current_cpu = 88110;
+ else
+ as_bad (_("Option `%s' is not recognized."), arg);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+md_show_usage (FILE *stream)
+{
+ fputs (_("\
+M88k options:\n\
+ -m88100 | -m88110 select processor type\n"),
+ stream);
+}
+
+#ifdef OBJ_ELF
+enum m88k_pic_reloc_type {
+ pic_reloc_none,
+ pic_reloc_abdiff,
+ pic_reloc_gotrel,
+ pic_reloc_plt
+};
+
+static bfd_reloc_code_real_type
+m88k_get_reloc_code(struct m88k_insn *insn)
+{
+ switch (insn->exp.X_md)
+ {
+ default:
+ case pic_reloc_none:
+ return insn->reloc;
+
+ case pic_reloc_abdiff:
+ if (insn->reloc == BFD_RELOC_LO16)
+ return BFD_RELOC_LO16_BASEREL;
+ if (insn->reloc == BFD_RELOC_HI16)
+ return BFD_RELOC_HI16_BASEREL;
+ break;
+
+ case pic_reloc_gotrel:
+ if (insn->reloc == BFD_RELOC_LO16)
+ return BFD_RELOC_LO16_GOTOFF;
+ if (insn->reloc == BFD_RELOC_HI16)
+ return BFD_RELOC_HI16_GOTOFF;
+ break;
+
+ case pic_reloc_plt:
+ if (insn->reloc == BFD_RELOC_32)
+ return BFD_RELOC_32_PLTOFF;
+ if (insn->reloc == BFD_RELOC_28_PCREL_S2)
+ return BFD_RELOC_32_PLT_PCREL;
+ break;
+ }
+
+ as_bad ("Can't process pic type %d relocation type %d",
+ insn->exp.X_md, insn->reloc);
+
+ return BFD_RELOC_NONE;
+}
+#else
+#define m88k_get_reloc_code(insn) (insn).reloc
+#endif
+\f
+void
+md_assemble (char *op)
+{
+ char *param, *thisfrag;
+ char c;
+ struct m88k_opcode *format;
+ struct m88k_insn insn;
+ fixS *fixP;
+
+ assert (op);
+
+ /* Skip over instruction to find parameters. */
+ for (param = op; *param != 0 && !ISSPACE (*param); param++)
+ ;
+ c = *param;
+ *param++ = '\0';
+
+ /* Try to find the instruction in the hash table. */
+ /* XXX will not match XRF flavours of 88100 instructions on 88110 */
+ if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL)
+ {
+ as_bad (_("Invalid mnemonic '%s'"), op);
+ return;
+ }
+
+ /* Try parsing this instruction into insn. */
+ insn.exp.X_add_symbol = 0;
+ insn.exp.X_op_symbol = 0;
+ insn.exp.X_add_number = 0;
+ insn.exp.X_op = O_illegal;
+ insn.exp.X_md = pic_reloc_none;
+ insn.reloc = NO_RELOC;
+
+ while (!calcop (format, param, &insn))
+ {
+ /* If it doesn't parse try the next instruction. */
+ if (!strcmp (format[0].name, format[1].name))
+ format++;
+ else
+ {
+ as_fatal (_("Parameter syntax error"));
+ return;
+ }
+ }
+
+ /* Grow the current frag and plop in the opcode. */
+ thisfrag = frag_more (4);
+ md_number_to_chars (thisfrag, insn.opcode, 4);
+
+ /* If this instruction requires labels mark it for later. */
+ switch (insn.reloc)
+ {
+ case NO_RELOC:
+ break;
+
+ case RELOC_LO16:
+ case RELOC_HI16:
+ fixP = fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal + 2,
+ 2,
+ &insn.exp,
+ 0,
+ m88k_get_reloc_code(&insn));
+ fixP->fx_no_overflow = 1;
+ break;
+
+#ifdef M88KCOFF
+ case RELOC_IW16:
+ fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal,
+ 4,
+ &insn.exp,
+ 0,
+ m88k_get_reloc_code(&insn));
+ break;
+#endif
+
+ case RELOC_PC16:
+#ifdef OBJ_ELF
+ fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal ,
+ 4,
+ &insn.exp,
+ 1,
+ m88k_get_reloc_code(&insn));
+#else
+ fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal + 2,
+ 2,
+ &insn.exp,
+ 1,
+ m88k_get_reloc_code(&insn));
+#endif
+ break;
+
+ case RELOC_PC26:
+ fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal,
+ 4,
+ &insn.exp,
+ 1,
+ m88k_get_reloc_code(&insn));
+ break;
+
+ case RELOC_32:
+ fix_new_exp (frag_now,
+ thisfrag - frag_now->fr_literal,
+ 4,
+ &insn.exp,
+ 0,
+ m88k_get_reloc_code(&insn));
+ break;
+
+ default:
+ as_fatal (_("Unknown relocation type"));
+ break;
+ }
+}
+
+static int
+calcop (struct m88k_opcode *format, char *param, struct m88k_insn *insn)
+{
+ char *fmt = format->op_spec;
+ int f;
+ unsigned val;
+ unsigned opcode;
+ unsigned int reg_prefix = 'r';
+
+ insn->opcode = format->opcode;
+ opcode = 0;
+
+ /*
+ * Instructions which have no arguments (such as rte) will get
+ * correctly reported only if param == "", although there could be
+ * whitespace following the instruction.
+ * Rather than eating whitespace here, let's assume everything is
+ * fine. If there were non-wanted arguments, they will be parsed as
+ * an incorrect opcode at the offending line, so that's not too bad.
+ * -- miod
+ */
+ if (*fmt == '\0')
+ return 1;
+
+ for (;;)
+ {
+ if (param == NULL)
+ return 0;
+
+ f = *fmt++;
+ switch (f)
+ {
+ case 0:
+ insn->opcode |= opcode;
+ return (*param == 0 || *param == '\n');
+
+ default:
+ if (f != *param++)
+ return 0;
+ break;
+
+ case 'd':
+ param = get_reg (param, &val, reg_prefix);
+ reg_prefix = 'r';
+ opcode |= val << 21;
+ break;
+
+ case 'o':
+ param = get_o6 (param, &val);
+ opcode |= ((val >> 2) << 7);
+ break;
+
+ case 'x':
+ reg_prefix = 'x';
+ break;
+
+ case '1':
+ param = get_reg (param, &val, reg_prefix);
+ reg_prefix = 'r';
+ opcode |= val << 16;
+ break;
+
+ case '2':
+ param = get_reg (param, &val, reg_prefix);
+ reg_prefix = 'r';
+ opcode |= val;
+ break;
+
+ case '3':
+ param = get_reg (param, &val, 'r');
+ opcode |= (val << 16) | val;
+ break;
+
+ case 'I':
+ param = get_imm16 (param, insn);
+ break;
+
+ case 'b':
+ param = get_bf (param, &val);
+ opcode |= val;
+ break;
+
+ case 'p':
+ param = get_pcr (param, insn, RELOC_PC16);
+ break;
+
+ case 'P':
+ param = get_pcr (param, insn, RELOC_PC26);
+ break;
+
+ case 'B':
+ param = get_cmp (param, &val);
+ opcode |= val;
+ break;
+
+ case 'M':
+ param = get_cnd (param, &val);
+ opcode |= val;
+ break;
+
+ case 'c':
+ param = get_cr (param, &val);
+ opcode |= val << 5;
+ break;
+
+ case 'f':
+ param = get_fcr (param, &val);
+ opcode |= val << 5;
+ break;
+
+ case 'V':
+ param = get_vec9 (param, &val);
+ opcode |= val;
+ break;
+
+ case '?':
+ /* Having this here repeats the warning sometimes.
+ But can't we stand that? */
+ as_warn (_("Use of obsolete instruction"));
+ break;
+ }
+ }
+}
+
+static char *
+match_name (char *param, struct field_val_assoc *assoc_tab, unsigned *valp)
+{
+ int i;
+ char *name;
+ int name_len;
+
+ for (i = 0;; i++)
+ {
+ name = assoc_tab[i].name;
+ if (name == NULL)
+ return NULL;
+ name_len = strlen (name);
+ if (!strncmp (param, name, name_len))
+ {
+ *valp = assoc_tab[i].val;
+ return param + name_len;
+ }
+ }
+}
+
+static char *
+get_reg (char *param, unsigned *regnop, unsigned int reg_prefix)
+{
+ unsigned c;
+ unsigned regno;
+
+#ifdef REGISTER_PREFIX
+ c = *param++;
+ if (c != REGISTER_PREFIX)
+ return NULL;
+#endif
+
+ c = *param++;
+ if (c == reg_prefix)
+ {
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 32)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+ else if (c == 's' && param[0] == 'p')
+ {
+ *regnop = 31;
+ return param + 1;
+ }
+
+ return NULL;
+}
+
+static char *
+get_imm16 (char *param, struct m88k_insn *insn)
+{
+ enum m88k_reloc_type reloc = NO_RELOC;
+ unsigned int val;
+ char *save_ptr;
+#ifdef REGISTER_PREFIX
+ int found_prefix = 0;
+#endif
+
+#ifdef REGISTER_PREFIX
+ if (*param == REGISTER_PREFIX)
+ {
+ param++;
+ found_prefix = 1;
+ }
+#endif
+
+ if (!strncmp (param, "hi16", 4) && !ISALNUM (param[4]))
+ {
+ reloc = RELOC_HI16;
+ param += 4;
+ }
+ else if (!strncmp (param, "lo16", 4) && !ISALNUM (param[4]))
+ {
+ reloc = RELOC_LO16;
+ param += 4;
+ }
+#ifdef M88KCOFF
+ else if (!strncmp (param, "iw16", 4) && !ISALNUM (param[4]))
+ {
+ reloc = RELOC_IW16;
+ param += 4;
+ }
+#endif
+
+#ifdef REGISTER_PREFIX
+ if (found_prefix && reloc == NO_RELOC)
+ return NULL;
+#endif
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ expression (&insn->exp);
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ val = insn->exp.X_add_number;
+
+ if (insn->exp.X_op == O_constant)
+ {
+ /* Insert the value now, and reset reloc to NO_RELOC. */
+ if (reloc == NO_RELOC)
+ {
+ /* Warn about too big expressions if not surrounded by xx16. */
+ if (val > 0xffff)
+ as_warn (_("Expression truncated to 16 bits"));
+ }
+
+ if (reloc == RELOC_HI16)
+ val >>= 16;
+
+ insn->opcode |= val & 0xffff;
+ reloc = NO_RELOC;
+ }
+ else if (reloc == NO_RELOC)
+ /* We accept a symbol even without lo16, hi16, etc, and assume
+ lo16 was intended. */
+ reloc = RELOC_LO16;
+
+ insn->reloc = reloc;
+
+ return param;
+}
+
+static char *
+get_pcr (char *param, struct m88k_insn *insn, enum m88k_reloc_type reloc)
+{
+ char *saveptr, *saveparam;
+
+ saveptr = input_line_pointer;
+ input_line_pointer = param;
+
+ expression (&insn->exp);
+
+ saveparam = input_line_pointer;
+ input_line_pointer = saveptr;
+
+ /* Botch: We should relocate now if O_constant. */
+ insn->reloc = reloc;
+
+ return saveparam;
+}
+
+static char *
+get_cmp (char *param, unsigned *valp)
+{
+ unsigned int val;
+ char *save_ptr;
+
+ save_ptr = param;
+
+#ifdef REGISTER_PREFIX
+ /* SVR4 compiler prefixes condition codes with the register prefix */
+ if (*param == REGISTER_PREFIX)
+ param++;
+#endif
+ param = match_name (param, cmpslot, valp);
+ val = *valp;
+
+ if (param == NULL)
+ {
+ param = save_ptr;
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ val = get_absolute_expression ();
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ if (val >= 32)
+ {
+ as_warn (_("Expression truncated to 5 bits"));
+ val %= 32;
+ }
+ }
+
+ *valp = val << 21;
+ return param;
+}
+
+static char *
+get_cnd (char *param, unsigned *valp)
+{
+ unsigned int val;
+
+ if (ISDIGIT (*param))
+ {
+ param = getval (param, &val);
+
+ if (val >= 32)
+ {
+ as_warn (_("Expression truncated to 5 bits"));
+ val %= 32;
+ }
+ }
+ else
+ {
+#ifdef REGISTER_PREFIX
+ /* SVR4 compiler prefixes condition codes with the register prefix */
+ if (*param == REGISTER_PREFIX)
+ param++;
+#endif
+
+ param[0] = TOLOWER (param[0]);
+ param[1] = TOLOWER (param[1]);
+
+ param = match_name (param, cndmsk, valp);
+
+ if (param == NULL)
+ return NULL;
+
+ val = *valp;
+ }
+
+ *valp = val << 21;
+ return param;
+}
+
+static char *
+get_bf2 (char *param, int bc)
+{
+ int depth = 0;
+ int c;
+
+ for (;;)
+ {
+ c = *param;
+ if (c == 0)
+ return param;
+ else if (c == '(')
+ depth++;
+ else if (c == ')')
+ depth--;
+ else if (c == bc && depth <= 0)
+ return param;
+ param++;
+ }
+}
+
+static char *
+get_bf_offset_expression (char *param, unsigned *offsetp)
+{
+ unsigned offset;
+
+#ifdef REGISTER_PREFIX
+ /* SVR4 compiler prefixes condition codes with the register prefix */
+ if (*param == REGISTER_PREFIX && ISALPHA (param[1]))
+ param++;
+#endif
+
+ if (ISALPHA (param[0]))
+ {
+ param[0] = TOLOWER (param[0]);
+ param[1] = TOLOWER (param[1]);
+
+ param = match_name (param, cmpslot, offsetp);
+
+ return param;
+ }
+ else
+ {
+ input_line_pointer = param;
+ offset = get_absolute_expression ();
+ param = input_line_pointer;
+ }
+
+ *offsetp = offset;
+ return param;
+}
+
+static char *
+get_bf (char *param, unsigned *valp)
+{
+ unsigned offset = 0;
+ unsigned width = 0;
+ char *xp;
+ char *save_ptr;
+
+ xp = get_bf2 (param, '<');
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ if (*xp == 0)
+ {
+ /* We did not find '<'. We have an offset (width implicitly 32). */
+ param = get_bf_offset_expression (param, &offset);
+ input_line_pointer = save_ptr;
+ if (param == NULL)
+ return NULL;
+ }
+ else
+ {
+ *xp++ = 0; /* Overwrite the '<' */
+ param = get_bf2 (xp, '>');
+ if (*param == 0)
+ return NULL;
+ *param++ = 0; /* Overwrite the '>' */
+
+ width = get_absolute_expression ();
+ xp = get_bf_offset_expression (xp, &offset);
+ input_line_pointer = save_ptr;
+
+ if (xp + 1 != param)
+ return NULL;
+ }
+
+ *valp = ((width % 32) << 5) | (offset % 32);
+
+ return param;
+}
+
+static char *
+get_cr (char *param, unsigned *regnop)
+{
+ unsigned regno;
+ unsigned c;
+
+#ifdef REGISTER_PREFIX
+ if (*param++ != REGISTER_PREFIX)
+ return NULL;
+#endif
+
+ if (!strncmp (param, "cr", 2))
+ {
+ param += 2;
+
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 64)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+
+ param = match_name (param,
+ current_cpu == 88110 ? m88110_cr_regs : m88100_cr_regs,
+ regnop);
+
+ return param;
+}
+
+static char *
+get_fcr (char *param, unsigned *regnop)
+{
+ unsigned regno;
+ unsigned c;
+
+#ifdef REGISTER_PREFIX
+ if (*param++ != REGISTER_PREFIX)
+ return NULL;
+#endif
+
+ if (!strncmp (param, "fcr", 3))
+ {
+ param += 3;
+
+ regno = *param++ - '0';
+ if (regno < 10)
+ {
+ if (regno == 0)
+ {
+ *regnop = 0;
+ return param;
+ }
+ c = *param - '0';
+ if (c < 10)
+ {
+ regno = regno * 10 + c;
+ if (c < 64)
+ {
+ *regnop = regno;
+ return param + 1;
+ }
+ }
+ else
+ {
+ *regnop = regno;
+ return param;
+ }
+ }
+ return NULL;
+ }
+
+ param = match_name (param, fcr_regs, regnop);
+
+ return param;
+}
+
+static char *
+get_vec9 (char *param, unsigned *valp)
+{
+ unsigned val;
+ char *save_ptr;
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ val = get_absolute_expression ();
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ if (val >= 1 << 9)
+ as_warn (_("Expression truncated to 9 bits"));
+
+ *valp = val % (1 << 9);
+
+ return param;
+}
+
+static char *
+get_o6 (char *param, unsigned *valp)
+{
+ unsigned val;
+ char *save_ptr;
+
+ save_ptr = input_line_pointer;
+ input_line_pointer = param;
+ val = get_absolute_expression ();
+ param = input_line_pointer;
+ input_line_pointer = save_ptr;
+
+ if (val & 0x3)
+ as_warn (_("Removed lower 2 bits of expression"));
+
+ *valp = val;
+
+ return (param);
+}
+
+#define hexval(z) \
+ (ISDIGIT (z) ? (z) - '0' : \
+ ISLOWER (z) ? (z) - 'a' + 10 : \
+ ISUPPER (z) ? (z) - 'A' + 10 : (unsigned) -1)
+
+static char *
+getval (char *param, unsigned int *valp)
+{
+ unsigned int val = 0;
+ unsigned int c;
+
+ c = *param++;
+ if (c == '0')
+ {
+ c = *param++;
+ if (c == 'x' || c == 'X')
+ {
+ c = *param++;
+ c = hexval (c);
+ while (c < 16)
+ {
+ val = val * 16 + c;
+ c = *param++;
+ c = hexval (c);
+ }
+ }
+ else
+ {
+ c -= '0';
+ while (c < 8)
+ {
+ val = val * 8 + c;
+ c = *param++ - '0';
+ }
+ }
+ }
+ else
+ {
+ c -= '0';
+ while (c < 10)
+ {
+ val = val * 10 + c;
+ c = *param++ - '0';
+ }
+ }
+
+ *valp = val;
+ return param - 1;
+}
+
+void
+md_number_to_chars (char *buf, valueT val, int nbytes)
+{
+ number_to_chars_bigendian (buf, val, nbytes);
+}
+
+#define MAX_LITTLENUMS 6
+
+/* 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.
+ */
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char *t;
+
+ switch (type)
+ {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ 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);
+ for (wordP = words; prec--;)
+ {
+ md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
+ return 0;
+}
+\f
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+
+void
+md_create_short_jump (char *ptr, addressT from_addr ATTRIBUTE_UNUSED,
+ addressT to_addr ATTRIBUTE_UNUSED, fragS *frag, symbolS *to_symbol)
+{
+ /* Since all instructions have the same width, it does not make sense to
+ try and abuse a conditional instruction to get a short displacement
+ (such as bb1 0, %r0, address). */
+ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol);
+}
+
+void
+md_create_long_jump (char *ptr, addressT from_addr ATTRIBUTE_UNUSED,
+ addressT to_addr ATTRIBUTE_UNUSED, fragS *frag, symbolS *to_symbol)
+{
+ ptr[0] = (char) 0xc0; /* br to_addr */
+ ptr[1] = 0x00;
+ ptr[2] = 0x00;
+ ptr[3] = 0x00;
+ fix_new (frag,
+ ptr - frag->fr_literal,
+ 4,
+ to_symbol,
+ (offsetT) 0,
+ 0,
+ RELOC_PC26);
+}
+
+int
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
+ segT segment_type ATTRIBUTE_UNUSED)
+{
+ as_fatal (_("Relaxation should never occur"));
+ return (-1);
+}
+
+#ifdef M88KCOFF
+
+/* These functions are needed if we are linking with obj-coffbfd.c.
+ That file may be replaced by a more BFD oriented version at some
+ point. If that happens, these functions should be reexamined.
+
+ Ian Lance Taylor, Cygnus Support, 13 July 1993. */
+
+/* Given a fixS structure (created by a call to fix_new, above),
+ return the BFD relocation type to use for it. */
+
+short
+tc_coff_fix2rtype (fixS *fixp)
+{
+ switch (fixp->fx_r_type)
+ {
+ case RELOC_LO16:
+ return R_LVRT16;
+ case RELOC_HI16:
+ return R_HVRT16;
+ case RELOC_PC16:
+ return R_PCR16L;
+ case RELOC_PC26:
+ return R_PCR26L;
+ case RELOC_32:
+ return R_VRT32;
+ case RELOC_IW16:
+ return R_VRT16;
+ default:
+ abort ();
+ }
+}
+
+/* Apply a fixS to the object file. Since COFF does not use addends
+ in relocs, the addend is actually stored directly in the object
+ file itself. */
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+ long val = * (long *) valP;
+ char *buf;
+
+ buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+ fixP->fx_addnumber = val;
+ fixP->fx_offset = 0;
+
+ switch (fixP->fx_r_type)
+ {
+ case RELOC_IW16:
+ fixP->fx_offset = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ case RELOC_LO16:
+ fixP->fx_offset = val >> 16;
+ buf[0] = val >> 8;
+ buf[1] = val;
+ break;
+
+ case RELOC_HI16:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ break;
+
+ case RELOC_PC16:
+ buf[0] = val >> 10;
+ buf[1] = val >> 2;
+ break;
+
+ case RELOC_PC26:
+ buf[0] |= (val >> 26) & 0x03;
+ buf[1] = val >> 18;
+ buf[2] = val >> 10;
+ buf[3] = val >> 2;
+ break;
+
+ case RELOC_32:
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+ fixP->fx_done = 1;
+}
+
+#endif /* M88KCOFF */
+
+/* Fill in rs_align_code fragments. */
+
+void
+m88k_handle_align (fragS *fragp)
+{
+ static const unsigned char nop_pattern[] = { 0xf4, 0x00, 0x58, 0x00 };
+
+ int bytes;
+ char *p;
+
+ if (fragp->fr_type != rs_align_code)
+ return;
+
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ p = fragp->fr_literal + fragp->fr_fix;
+
+ if (bytes & 3)
+ {
+ int fix = bytes & 3;
+ memset (p, 0, fix);
+ p += fix;
+ bytes -= fix;
+ fragp->fr_fix += fix;
+ }
+
+ memcpy (p, nop_pattern, 4);
+ fragp->fr_var = 4;
+}
+
+/* Where a PC relative offset is calculated from. On the m88k they
+ are calculated from just after the instruction. */
+
+long
+md_pcrel_from (fixS *fixp)
+{
+ switch (fixp->fx_r_type)
+ {
+ case RELOC_PC16:
+#ifdef OBJ_ELF
+ /* FALLTHROUGH */
+#else
+ return fixp->fx_frag->fr_address + fixp->fx_where - 2;
+#endif
+ case RELOC_PC26:
+#ifdef OBJ_ELF
+ case BFD_RELOC_32_PLT_PCREL:
+#endif
+ return fixp->fx_frag->fr_address + fixp->fx_where;
+ default:
+ abort ();
+ }
+ /*NOTREACHED*/
+}
+
+#ifdef OBJ_ELF
+
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
+{
+ return size;
+}
+
+/* Generate the BFD reloc to be stuck in the object file from the
+ fixup used internally in the assembler. */
+
+arelent *
+tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixp)
+{
+ arelent *reloc;
+ bfd_reloc_code_real_type code;
+
+ reloc = (arelent *) xmalloc (sizeof (arelent));
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ /* Make sure none of our internal relocations make it this far.
+ They'd better have been fully resolved by this point. */
+ assert ((int) fixp->fx_r_type > 0);
+
+ code = fixp->fx_r_type;
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (reloc->howto == NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("cannot represent `%s' relocation in object file"),
+ bfd_get_reloc_code_name (code));
+ return NULL;
+ }
+
+ if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
+ {
+ as_fatal (_("internal error? cannot generate `%s' relocation"),
+ bfd_get_reloc_code_name (code));
+ }
+ assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
+
+ reloc->addend = fixp->fx_offset;
+
+ return reloc;
+}
+
+/* Apply a fixS to the object file. This is called for all the
+ fixups we generated by the call to fix_new_exp, above. In the call
+ above we used a reloc code which was the largest legal reloc code
+ plus the operand index. Here we undo that to recover the operand
+ index. At this point all symbol values should be fully resolved,
+ and we attempt to completely resolve the reloc. If we can not do
+ that, we determine the correct reloc code and put it back in the
+ fixup.
+
+ This is the ELF version.
+*/
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+ valueT val = * (valueT *) valP;
+ char *buf;
+ long insn;
+
+ buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ if (fixP->fx_subsy != NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+
+ if (fixP->fx_addsy)
+ {
+#if 0
+ /* can't empty 26-bit relocation values with memset() */
+ if (fixP->fx_r_type == BFD_RELOC_28_PCREL_S2)
+ {
+ insn = bfd_getb32 ((unsigned char *) buf);
+ insn &= ~0x03ffffff;
+ bfd_putb32(insn, buf);
+ }
+ else
+ memset(buf, 0, fixP->fx_size);
+#endif
+
+ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ && !S_IS_DEFINED (fixP->fx_addsy)
+ && !S_IS_WEAK (fixP->fx_addsy))
+ S_SET_WEAK (fixP->fx_addsy);
+
+ return;
+ }
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ return;
+
+ case BFD_RELOC_HI16_BASEREL:
+ case BFD_RELOC_LO16_BASEREL:
+ case BFD_RELOC_HI16_GOTOFF:
+ case BFD_RELOC_LO16_GOTOFF:
+ case BFD_RELOC_32_PLTOFF:
+ return;
+
+ case BFD_RELOC_LO16:
+ case BFD_RELOC_HI16:
+ if (fixP->fx_pcrel)
+ abort ();
+ buf[0] = val >> 8;
+ buf[1] = val;
+ break;
+
+ case BFD_RELOC_18_PCREL_S2:
+ if ((val & 0x03) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Branch to unaligned address (%lx)", (long)val);
+ buf[2] = val >> 10;
+ buf[3] = val >> 2;
+ break;
+
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_28_PCREL_S2:
+ if ((val & 0x03) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Branch to unaligned address (%lx)", (long)val);
+ buf[0] |= (val >> 26) & 0x03;
+ buf[1] = val >> 18;
+ buf[2] = val >> 10;
+ buf[3] = val >> 2;
+ break;
+
+ case BFD_RELOC_32:
+ insn = val;
+ bfd_putb32(insn, buf);
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (/* fixP->fx_addsy == NULL && */ fixP->fx_pcrel == 0)
+ fixP->fx_done = 1;
+}
+
+/* Set the ELF specific flags. */
+void
+m88k_elf_final_processing (void)
+{
+ if (current_cpu == 88110)
+ elf_elfheader (stdoutput)->e_flags |= EF_M88110;
+}
+
+inline static char *
+m88k_end_of_name (char *suffix, const char *pattern, size_t patlen)
+{
+ if (strncmp (suffix, pattern, patlen) == 0
+ && ! is_part_of_name (suffix[patlen]))
+ return suffix + patlen;
+
+ return NULL;
+}
+
+int
+m88k_parse_name (const char *name, expressionS *expressionP, char *nextcharP)
+{
+ char *next = input_line_pointer;
+ char *next_end;
+ enum m88k_pic_reloc_type reloc_type = pic_reloc_none;
+ symbolS *symbolP;
+ segT segment;
+
+ if (*nextcharP != '#')
+ return 0;
+
+ if ((next_end = m88k_end_of_name (next + 1, "abdiff", 6)) != NULL)
+ {
+ reloc_type = pic_reloc_abdiff;
+ }
+ else if ((next_end = m88k_end_of_name (next + 1, "got_rel", 7)) != NULL)
+ {
+ reloc_type = pic_reloc_gotrel;
+ }
+ else if ((next_end = m88k_end_of_name (next + 1, "plt", 3)) != NULL)
+ {
+ reloc_type = pic_reloc_plt;
+ }
+ else
+ return 0;
+
+ symbolP = symbol_find_or_make (name);
+ segment = S_GET_SEGMENT (symbolP);
+ if (segment == absolute_section)
+ {
+ expressionP->X_op = O_constant;
+ expressionP->X_add_number = S_GET_VALUE (symbolP);
+ }
+ else if (segment == reg_section)
+ {
+ expressionP->X_op = O_register;
+ expressionP->X_add_number = S_GET_VALUE (symbolP);
+ }
+ else
+ {
+ expressionP->X_op = O_symbol;
+ expressionP->X_add_symbol = symbolP;
+ expressionP->X_add_number = 0;
+ }
+ expressionP->X_md = reloc_type;
+
+ *input_line_pointer = *nextcharP;
+ input_line_pointer = next_end;
+ *nextcharP = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ return 1;
+}
+
+int
+m88k_fix_adjustable (fixS *fix)
+{
+ return (fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
+ && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
+ && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
+ && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
+ && (fix->fx_pcrel
+ || (fix->fx_subsy != NULL
+ && (S_GET_SEGMENT (fix->fx_subsy)
+ == S_GET_SEGMENT (fix->fx_addsy)))
+ || S_IS_LOCAL (fix->fx_addsy)));
+}
+#endif /* OBJ_ELF */
+
+#ifdef OBJ_AOUT
+
+/* Round up a section size to the appropriate boundary. */
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
+{
+ /* For a.out, force the section size to be aligned. If we don't do
+ this, BFD will align it for us, but it will not write out the
+ final bytes of the section. This may be a bug in BFD, but it is
+ easier to fix it here since that is how the other a.out targets
+ work. */
+ int align;
+
+ align = bfd_get_section_alignment (stdoutput, segment);
+ valueT mask = ((valueT) 1 << align) - 1;
+
+ return (size + mask) & ~mask;
+}
+
+const int md_reloc_size = 12; /* sizeof(struct relocation_info); */
+
+void
+tc_aout_fix_to_chars (char *where, fixS *fixP,
+ relax_addressT segment_address_in_file)
+{
+ long r_symbolnum;
+ long r_addend = 0;
+ long r_address;
+
+ know (fixP->fx_addsy != NULL);
+
+ r_address = fixP->fx_frag->fr_address + fixP->fx_where
+ - segment_address_in_file;
+ md_number_to_chars (where, r_address, 4);
+
+ r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
+ ? S_GET_TYPE (fixP->fx_addsy)
+ : fixP->fx_addsy->sy_number);
+
+ where[4] = (r_symbolnum >> 16) & 0x0ff;
+ where[5] = (r_symbolnum >> 8) & 0x0ff;
+ where[6] = r_symbolnum & 0x0ff;
+ where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x70) |
+ (fixP->fx_r_type & 0xf));
+
+ if (fixP->fx_addsy->sy_frag) {
+ r_addend = fixP->fx_addsy->sy_frag->fr_address;
+ }
+
+ if (fixP->fx_pcrel) {
+ r_addend -= r_address;
+ } else {
+ r_addend = fixP->fx_addnumber;
+ }
+
+ md_number_to_chars(&where[8], r_addend, 4);
+}
+
+void
+tc_headers_hook (object_headers *headers)
+{
+#if defined(TE_NetBSD) || defined(TE_OpenBSD)
+ N_SET_INFO(headers->header, OMAGIC, M_88K_OPENBSD, 0);
+ headers->header.a_info = htonl(headers->header.a_info);
+#endif
+}
+
+#endif /* OBJ_AOUT */
--- /dev/null
+/* m88k.h -- Assembler for the Motorola 88000
+ Contributed by Devon Bowen of Buffalo University
+ and Torbjorn Granlund of the Swedish Institute of Computer Science.
+ Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000,
+ 2002 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_M88K
+
+#define TARGET_BYTES_BIG_ENDIAN 1
+#undef REGISTER_PREFIX
+
+#ifdef OBJ_AOUT
+#ifdef TE_OpenBSD
+#define TARGET_FORMAT "a.out-m88k-openbsd"
+#endif
+#endif
+
+#ifdef M88KCOFF
+#define BFD_ARCH bfd_arch_m88k
+#define COFF_MAGIC MC88OMAGIC
+#define COFF_FLAGS F_AR32W
+#endif
+
+#ifdef OBJ_ELF
+#define BFD_ARCH bfd_arch_m88k
+#define TARGET_ARCH bfd_arch_m88k
+#define TARGET_FORMAT "elf32-m88k"
+#if defined(TE_OpenBSD)
+#define REGISTER_PREFIX '%'
+#else
+#define REGISTER_PREFIX '#'
+#endif
+#endif
+
+#define CUSTOM_RELOC_FORMAT
+
+/* different type of relocation available in the m88k */
+
+#include "bfd.h"
+#define m88k_reloc_type bfd_reloc_code_real
+
+#ifdef OBJ_ELF
+
+/* This is used to recognize #abdiff, #got_rel and #plt symbols.
+ The relocation type is stored in X_md. */
+extern int m88k_parse_name (const char *, expressionS *, char *);
+#define md_parse_name(s, e, m, c) m88k_parse_name (s, e, c)
+
+/* This expression evaluates to true if the relocation is for a local
+ object for which we still want to do the relocation at runtime.
+ False if we are willing to perform this relocation while building
+ the .o file. Only concerns pcrel relocs. */
+
+#define TC_FORCE_RELOCATION_LOCAL(FIX) \
+ (!(FIX)->fx_pcrel \
+ || (FIX)->fx_plt \
+ || (FIX)->fx_r_type == BFD_RELOC_32_PLT_PCREL \
+ || TC_FORCE_RELOCATION (FIX))
+
+/* Keep relocations relative to the GOT, or non-PC relative. */
+#define tc_fix_adjustable(FIX) m88k_fix_adjustable (FIX)
+extern int m88k_fix_adjustable (struct fix *);
+
+#endif /* OBJ_ELF */
+
+#ifndef OBJ_ELF
+/* The m88k uses '@' to start local labels, except on ELF. */
+#define LEX_AT (LEX_BEGIN_NAME | LEX_NAME)
+#endif /* OBJ_ELF */
+
+#if !defined(OBJ_ELF) || !defined(TE_OpenBSD)
+/* The m88k uses pseudo-ops with no leading period, except on OpenBSD ELF. */
+#define NO_PSEUDO_DOT 1
+#endif
+
+/* Don't warn on word overflow; it happens on %hi relocs. */
+#undef WARN_SIGNED_OVERFLOW_WORD
+
+#define md_convert_frag(b,s,f) {as_fatal (_("m88k convert_frag\n"));}
+
+/* We don't need to do anything special for undefined symbols. */
+#define md_undefined_symbol(s) 0
+
+/* We have no special operand handling. */
+#define md_operand(e)
+
+#define tc_aout_pre_write_hook(x) do { } while (0)
+#define tc_crawl_symbol_chain(a) do { } while (0)
+
+#ifdef M88KCOFF
+
+/* Whether a reloc should be output. */
+#define TC_COUNT_RELOC(fixp) ((fixp)->fx_addsy != NULL)
+
+/* Get the BFD reloc type to use for a gas fixS structure. */
+#define TC_COFF_FIX2RTYPE(fixp) tc_coff_fix2rtype (fixp)
+
+/* No special hook needed for symbols. */
+#define tc_coff_symbol_emit_hook(s)
+
+/* Align sections to a four byte boundary. */
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) max (section_alignment[(int) (SEG)], 4)
+
+#endif /* M88KCOFF */
+
+/* Fill in rs_align_code fragments. */
+extern void m88k_handle_align (fragS *);
+#define HANDLE_ALIGN(frag) m88k_handle_align (frag)
+
+#define MAX_MEM_FOR_RS_ALIGN_CODE (3 + 4)
+
+#define elf_tc_final_processing m88k_elf_final_processing
+extern void m88k_elf_final_processing (void);
+
+/* word pseudo outputs 32-bit values, no risk of ``broken words'' */
+#define WORKING_DOT_WORD
m68k-*-openbsd*) fmt=aout em=obsd bfd_gas=yes ;;
m68k-*-psos*) fmt=elf em=psos;;
+ m88k-*-openbsd*) fmt=elf em=obsd ;;
+
maxq-*-coff) fmt=coff bfd_gas=yes ;;
mcore-*-elf) fmt=elf ;;
--- /dev/null
+/* MC88k ELF support for BFD.
+ Copyright 1998, 1999, 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_M88K_H
+#define _ELF_M88K_H
+
+#include "elf/reloc-macros.h"
+
+/* Relocation types. */
+START_RELOC_NUMBERS (elf_m88k_reloc_type)
+ RELOC_NUMBER (R_88K_NONE, 0)
+ RELOC_NUMBER (R_88K_COPY, 1)
+ RELOC_NUMBER (R_88K_GOTP_ENT, 2)
+ RELOC_NUMBER (R_88K_8, 4)
+ RELOC_NUMBER (R_88K_8S, 5)
+ RELOC_NUMBER (R_88K_16S, 7)
+ RELOC_NUMBER (R_88K_DISP16, 8)
+ RELOC_NUMBER (R_88K_DISP26, 10)
+ RELOC_NUMBER (R_88K_PLT_DISP26, 14)
+ RELOC_NUMBER (R_88K_BBASED_32, 16)
+ RELOC_NUMBER (R_88K_BBASED_32UA, 17)
+ RELOC_NUMBER (R_88K_BBASED_16H, 18)
+ RELOC_NUMBER (R_88K_BBASED_16L, 19)
+ RELOC_NUMBER (R_88K_ABDIFF_32, 24)
+ RELOC_NUMBER (R_88K_ABDIFF_32UA, 25)
+ RELOC_NUMBER (R_88K_ABDIFF_16H, 26)
+ RELOC_NUMBER (R_88K_ABDIFF_16L, 27)
+ RELOC_NUMBER (R_88K_ABDIFF_16, 28)
+ RELOC_NUMBER (R_88K_32, 32)
+ RELOC_NUMBER (R_88K_32UA, 33)
+ RELOC_NUMBER (R_88K_16H, 34)
+ RELOC_NUMBER (R_88K_16L, 35)
+ RELOC_NUMBER (R_88K_16, 36)
+ RELOC_NUMBER (R_88K_GOT_32, 40)
+ RELOC_NUMBER (R_88K_GOT_32UA, 41)
+ RELOC_NUMBER (R_88K_GOT_16H, 42)
+ RELOC_NUMBER (R_88K_GOT_16L, 43)
+ RELOC_NUMBER (R_88K_GOT_16, 44)
+ RELOC_NUMBER (R_88K_GOTP_32, 48)
+ RELOC_NUMBER (R_88K_GOTP_32UA, 49)
+ RELOC_NUMBER (R_88K_GOTP_16H, 50)
+ RELOC_NUMBER (R_88K_GOTP_16L, 51)
+ RELOC_NUMBER (R_88K_GOTP_16, 52)
+ RELOC_NUMBER (R_88K_PLT_32, 56)
+ RELOC_NUMBER (R_88K_PLT_32UA, 57)
+ RELOC_NUMBER (R_88K_PLT_16H, 58)
+ RELOC_NUMBER (R_88K_PLT_16L, 59)
+ RELOC_NUMBER (R_88K_PLT_16, 60)
+ RELOC_NUMBER (R_88K_ABREL_32, 64)
+ RELOC_NUMBER (R_88K_ABREL_32UA, 65)
+ RELOC_NUMBER (R_88K_ABREL_16H, 66)
+ RELOC_NUMBER (R_88K_ABREL_16L, 67)
+ RELOC_NUMBER (R_88K_ABREL_16, 68)
+ RELOC_NUMBER (R_88K_GOT_ABREL_32, 72)
+ RELOC_NUMBER (R_88K_GOT_ABREL_32UA, 73)
+ RELOC_NUMBER (R_88K_GOT_ABREL_16H, 74)
+ RELOC_NUMBER (R_88K_GOT_ABREL_16L, 75)
+ RELOC_NUMBER (R_88K_GOT_ABREL_16, 76)
+ RELOC_NUMBER (R_88K_GOTP_ABREL_32, 80)
+ RELOC_NUMBER (R_88K_GOTP_ABREL_32UA, 81)
+ RELOC_NUMBER (R_88K_GOTP_ABREL_16H, 82)
+ RELOC_NUMBER (R_88K_GOTP_ABREL_16L, 83)
+ RELOC_NUMBER (R_88K_GOTP_ABREL_16, 84)
+ RELOC_NUMBER (R_88K_PLT_ABREL_32, 88)
+ RELOC_NUMBER (R_88K_PLT_ABREL_32UA, 89)
+ RELOC_NUMBER (R_88K_PLT_ABREL_16H, 90)
+ RELOC_NUMBER (R_88K_PLT_ABREL_16L, 91)
+ RELOC_NUMBER (R_88K_PLT_ABREL_16, 92)
+ RELOC_NUMBER (R_88K_SREL_32, 96)
+ RELOC_NUMBER (R_88K_SREL_32UA, 97)
+ RELOC_NUMBER (R_88K_SREL_16H, 98)
+ RELOC_NUMBER (R_88K_SREL_16L, 99)
+ /* These are GNU extensions to enable C++ vtable garbage collection. */
+ RELOC_NUMBER (R_88K_GNU_VTINHERIT, 100)
+ RELOC_NUMBER (R_88K_GNU_VTENTRY, 101)
+END_RELOC_NUMBERS (R_88K_UNIMPLEMENTED)
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+#define EF_NABI 0x80000000 /* not ABI compliant */
+#define EF_M88110 0x00000004 /* used 88110-specific features */
+
+/* Processor specific dynamic tag values. */
+
+#define DT_88K_ADDRBASE 0x70000001
+#define DT_88K_PLTSTART 0x70000002
+#define DT_88K_PLTEND 0x70000003
+#define DT_88K_TDESC 0x70000004
+
+#endif
eelf32lppcnto.o \
eelf32lppcsim.o \
eelf32m32c.o \
+ eelf32m88k.o \
+ eelf32m88k_obsd.o \
eelf32mcore.o \
eelf32mipswindiss.o \
eelf32mt.o \
em68kobsd.o \
em68kpsos.o \
em88kbcs.o \
+ em88kopenbsd.o \
emaxqcoff.o \
emcorepe.o \
emipsbig.o \
em88kbcs.c: $(srcdir)/emulparams/m88kbcs.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/m88kbcs.sc ${GEN_DEPENDS}
${GENSCRIPTS} m88kbcs "$(tdir_m88kbcs)"
+em88kopenbsd.c: $(srcdir)/emulparams/m88kopenbsd.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} m88kopenbsd "$(tdir_m88kopenbsd)"
emaxqcoff.c: $(srcdir)/emulparams/maxqcoff.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/maxqcoff.sc ${GEN_DEPENDS}
${GENSCRIPTS} maxqcoff "$(tdir_maxqcoff)"
$(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/needrelax.em \
$(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32m32c "$(tdir_m32c)"
+eelf32m88k.c: $(srcdir)/emulparams/elf32m88k.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32m88k "$(tdir_elf32m88k)"
+eelf32m88k_obsd.c: $(srcdir)/emulparams/elf32m88k_obsd.sh \
+ $(srcdir)/emulparams/elf32m88k.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32m88k_obsd "$(tdir_elf32m88k_obsd)"
eelf32mt.c: $(srcdir)/emulparams/elf32mt.sh \
$(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32mt "$(tdir_mt)"
eelf32lppcnto.o \
eelf32lppcsim.o \
eelf32m32c.o \
+ eelf32m88k.o \
+ eelf32m88k_obsd.o \
eelf32mcore.o \
eelf32mipswindiss.o \
eelf32mt.o \
em68kobsd.o \
em68kpsos.o \
em88kbcs.o \
+ em88kopenbsd.o \
emaxqcoff.o \
emcorepe.o \
emipsbig.o \
em88kbcs.c: $(srcdir)/emulparams/m88kbcs.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/m88kbcs.sc ${GEN_DEPENDS}
${GENSCRIPTS} m88kbcs "$(tdir_m88kbcs)"
+em88kopenbsd.c: $(srcdir)/emulparams/m88kopenbsd.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} m88kopenbsd "$(tdir_m88kopenbsd)"
emaxqcoff.c: $(srcdir)/emulparams/maxqcoff.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/maxqcoff.sc ${GEN_DEPENDS}
${GENSCRIPTS} maxqcoff "$(tdir_maxqcoff)"
$(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/needrelax.em \
$(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32m32c "$(tdir_m32c)"
+eelf32m88k.c: $(srcdir)/emulparams/elf32m88k.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32m88k "$(tdir_elf32m88k)"
+eelf32m88k_obsd.c: $(srcdir)/emulparams/elf32m88k_obsd.sh \
+ $(srcdir)/emulparams/elf32m88k.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32m88k_obsd "$(tdir_elf32m88k_obsd)"
eelf32mt.c: $(srcdir)/emulparams/elf32mt.sh \
$(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32mt "$(tdir_mt)"
m68*-*-rtemscoff*) targ_emul=m68kcoff ;;
m68*-*-rtems*) targ_emul=m68kelf
;;
-m8*-*-*) targ_emul=m88kbcs
+m88*-*-openbsd*) targ_emul=elf32m88k_obsd
+ targ_extra_emul="m88kopenbsd m88kbcs" ;;
+m88*-*-*) targ_emul=m88kbcs
;;
maxq-*-coff) targ_emul=maxqcoff
;;
--- /dev/null
+SCRIPT_NAME=elf
+OUTPUT_FORMAT="elf32-m88k"
+TEXT_START_ADDR=0x1000
+MAXPAGESIZE=0x10000
+COMMONPAGESIZE=0x1000
+NONPAGED_TEXT_START_ADDR=0x1000
+ARCH=m88k
+MACHINE=
+NOP=0xf4005800
+TEMPLATE_NAME=elf32
+NO_SMALL_DATA=yes
--- /dev/null
+. ${srcdir}/emulparams/elf32m88k.sh
+# Force padding around .plt
+DATA_PLT=
+GENERATE_SHLIB_SCRIPT=yes
+GENERATE_PIE_SCRIPT=no
+. ${srcdir}/emulparams/elf_obsd.sh
--- /dev/null
+SCRIPT_NAME=aout
+TEXT_START_ADDR=0x1020
+NONPAGED_TEXT_START_ADDR=0x1000
+OUTPUT_FORMAT="a.out-m88k-openbsd"
+TARGET_PAGE_SIZE=0x1000
+ARCH=m88k