# --- T2-COPYRIGHT-BEGIN --- # t2/package/*/binutils/i860.patch.i860 # Copyright (C) 2026 The T2 SDE Project # SPDX-License-Identifier: GPL-2.0 or patched project license # --- T2-COPYRIGHT-END --- From: René Rebe Subject: [PATCH] i860: restore the target for binutils, add Linux, dynamic linking and TLS Restores the i860 port removed from binutils in 2018: bfd, opcodes, gas and ld with i860-*-linux*, dynamic linking and TLS relocations. Generated configure and Makefile.in were patched by hand and not regenerated. For the binutils-2.47 release tarball. Tested in the MAME magicst2 model only, not on real hardware. Signed-off-by: René Rebe Co-Authored-By: Claude Opus 5.5 --- bfd/Makefile.am | 5 + bfd/Makefile.in | 6 + bfd/archures.c | 4 + bfd/bfd-in2.h | 43 + bfd/config.bfd | 14 +- bfd/configure | 2 + bfd/configure.ac | 3 + bfd/cpu-i860.c | 44 + bfd/elf32-i860.c | 2601 +++++++++++++++++++++++++++++++++++ bfd/libbfd.h | 40 + bfd/po/SRC-POTFILES.in | 2 + bfd/reloc.c | 84 ++ bfd/targets.c | 5 + gas/Makefile.am | 3 + gas/Makefile.in | 6 + gas/config/tc-i860.c | 1614 ++++++++++++++++++++++ gas/config/tc-i860.h | 101 ++ gas/configure.tgt | 2 + gas/doc/all.texi | 1 + gas/doc/as.texi | 9 +- gas/doc/c-i860.texi | 197 +++ gas/doc/local.mk | 1 + gas/po/POTFILES.in | 2 + include/elf/i860.h | 11 + include/opcode/i860.h | 507 +++++++ ld/Makefile.am | 2 + ld/Makefile.in | 2 + ld/configure.tgt | 6 + ld/emulparams/elf32_i860.sh | 24 + ld/po/BLD-POTFILES.in | 1 + opcodes/Makefile.am | 2 + opcodes/Makefile.in | 2 + opcodes/configure | 1 + opcodes/configure.ac | 2 + opcodes/disassemble.c | 7 + opcodes/disassemble.h | 2 + opcodes/i860-dis.c | 287 ++++ opcodes/po/POTFILES.in | 1 + 38 files changed, 5644 insertions(+), 2 deletions(-) diff --git a/bfd/Makefile.am b/bfd/Makefile.am index e4df05441eb..c408c90f8ee 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to generate Makefile.in # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -117,6 +118,7 @@ ALL_MACHINES = \ cpu-h8300.lo \ cpu-hppa.lo \ cpu-i386.lo \ + cpu-i860.lo \ cpu-ia64.lo \ cpu-iamcu.lo \ cpu-ip2k.lo \ @@ -200,6 +202,7 @@ ALL_MACHINES_CFILES = \ cpu-h8300.c \ cpu-hppa.c \ cpu-i386.c \ + cpu-i860.c \ cpu-ia64.c \ cpu-iamcu.c \ cpu-ip2k.c \ @@ -315,6 +318,7 @@ BFD32_BACKENDS = \ elf32-h8300.lo \ elf32-hppa.lo \ elf32-i386.lo \ + elf32-i860.lo \ elf32-ip2k.lo \ elf32-iq2000.lo \ elf32-lm32.lo \ @@ -450,6 +454,7 @@ BFD32_BACKENDS_CFILES = \ elf32-h8300.c \ elf32-hppa.c \ elf32-i386.c \ + elf32-i860.c \ elf32-ip2k.c \ elf32-iq2000.c \ elf32-lm32.c \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index 14512cf61fb..1d593fd7cc8 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -585,6 +585,7 @@ ALL_MACHINES = \ cpu-h8300.lo \ cpu-hppa.lo \ cpu-i386.lo \ + cpu-i860.lo \ cpu-ia64.lo \ cpu-iamcu.lo \ cpu-ip2k.lo \ @@ -668,6 +669,7 @@ ALL_MACHINES_CFILES = \ cpu-h8300.c \ cpu-hppa.c \ cpu-i386.c \ + cpu-i860.c \ cpu-ia64.c \ cpu-iamcu.c \ cpu-ip2k.c \ @@ -784,6 +786,7 @@ BFD32_BACKENDS = \ elf32-h8300.lo \ elf32-hppa.lo \ elf32-i386.lo \ + elf32-i860.lo \ elf32-ip2k.lo \ elf32-iq2000.lo \ elf32-lm32.lo \ @@ -919,6 +922,7 @@ BFD32_BACKENDS_CFILES = \ elf32-h8300.c \ elf32-hppa.c \ elf32-i386.c \ + elf32-i860.c \ elf32-ip2k.c \ elf32-iq2000.c \ elf32-lm32.c \ @@ -1497,6 +1501,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-h8300.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-hppa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-i386.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-i860.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ia64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-iamcu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ip2k.Plo@am__quote@ @@ -1592,6 +1597,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-h8300.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-hppa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-i386.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-i860.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ia64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ip2k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-iq2000.Plo@am__quote@ diff --git a/bfd/archures.c b/bfd/archures.c index 0e919246673..38797a23c38 100644 --- a/bfd/archures.c +++ b/bfd/archures.c @@ -1,5 +1,6 @@ /* BFD library support routines for architectures. Copyright (C) 1990-2026 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -197,6 +198,7 @@ DESCRIPTION .#define bfd_mach_mipsisa64r5 68 .#define bfd_mach_mipsisa64r6 69 .#define bfd_mach_mips_micromips 96 +. bfd_arch_i860, {* Intel 860. *} . bfd_arch_i386, {* Intel 386. *} .#define bfd_mach_i386_intel_syntax (1 << 0) .#define bfd_mach_i386_i8086 (1 << 1) @@ -664,6 +666,7 @@ extern const bfd_arch_info_type bfd_frv_arch; extern const bfd_arch_info_type bfd_h8300_arch; extern const bfd_arch_info_type bfd_hppa_arch; extern const bfd_arch_info_type bfd_i386_arch; +extern const bfd_arch_info_type bfd_i860_arch; extern const bfd_arch_info_type bfd_iamcu_arch; extern const bfd_arch_info_type bfd_ia64_arch; extern const bfd_arch_info_type bfd_ip2k_arch; @@ -752,6 +755,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_h8300_arch, &bfd_hppa_arch, &bfd_i386_arch, + &bfd_i860_arch, &bfd_iamcu_arch, &bfd_ia64_arch, &bfd_ip2k_arch, diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index e49d67316f3..ffc65223a80 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1454,6 +1454,7 @@ enum bfd_architecture #define bfd_mach_mipsisa64r5 68 #define bfd_mach_mipsisa64r6 69 #define bfd_mach_mips_micromips 96 + bfd_arch_i860, /* Intel 860. */ bfd_arch_i386, /* Intel 386. */ #define bfd_mach_i386_intel_syntax (1 << 0) #define bfd_mach_i386_i8086 (1 << 1) @@ -5926,6 +5927,48 @@ enum bfd_reloc_code_real BFD_RELOC_CRIS_DTPMOD, BFD_RELOC_CRIS_32_IE, + /* Intel i860 Relocations. */ + BFD_RELOC_860_COPY, + BFD_RELOC_860_GLOB_DAT, + BFD_RELOC_860_JUMP_SLOT, + BFD_RELOC_860_RELATIVE, + BFD_RELOC_860_PC26, + BFD_RELOC_860_PLT26, + BFD_RELOC_860_PC16, + BFD_RELOC_860_LOW0, + BFD_RELOC_860_SPLIT0, + BFD_RELOC_860_LOW1, + BFD_RELOC_860_SPLIT1, + BFD_RELOC_860_LOW2, + BFD_RELOC_860_SPLIT2, + BFD_RELOC_860_LOW3, + BFD_RELOC_860_LOGOT0, + BFD_RELOC_860_SPGOT0, + BFD_RELOC_860_LOGOT1, + BFD_RELOC_860_SPGOT1, + BFD_RELOC_860_LOGOTOFF0, + BFD_RELOC_860_SPGOTOFF0, + BFD_RELOC_860_LOGOTOFF1, + BFD_RELOC_860_SPGOTOFF1, + BFD_RELOC_860_LOGOTOFF2, + BFD_RELOC_860_LOGOTOFF3, + BFD_RELOC_860_LOPC, + BFD_RELOC_860_HIGHADJ, + BFD_RELOC_860_HAGOT, + BFD_RELOC_860_HAGOTOFF, + BFD_RELOC_860_HAPC, + BFD_RELOC_860_HIGH, + BFD_RELOC_860_HIGOT, + BFD_RELOC_860_HIGOTOFF, + BFD_RELOC_860_TLS_GD_HI, + BFD_RELOC_860_TLS_GD_LO, + BFD_RELOC_860_TLS_IE_HA, + BFD_RELOC_860_TLS_IE_LO1, + BFD_RELOC_860_TLS_IE_ABS_HA, + BFD_RELOC_860_TLS_IE_ABS_LO1, + BFD_RELOC_860_TLS_LE_HI, + BFD_RELOC_860_TLS_LE_LO, + /* OpenRISC 1000 Relocations. */ BFD_RELOC_OR1K_REL_26, BFD_RELOC_OR1K_SLO16, diff --git a/bfd/config.bfd b/bfd/config.bfd index 02a1a68525e..2c982e87ade 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -1,6 +1,7 @@ # config.bfd # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -125,7 +126,6 @@ case $targ in i[3-7]86-none-* | \ i[3-7]86-*-aout* | i[3-7]86*-*-vsta* | \ i370-* | \ - i860-*-* | \ i960-*-* | \ m68*-*-bsd* | \ m68*-*-aout* | \ @@ -649,6 +649,18 @@ case "${targ}" in targ_selvecs="i386_msdos_vec i386_aout_vec" ;; + i860-*-linux*) + targ_defvec=i860_elf32_le_vec + targ_selvecs=i860_elf32_vec + ;; + i860-stardent-sysv4* | i860-stardent-elf*) + targ_defvec=i860_elf32_le_vec + targ_selvecs="i860_elf32_vec i860_elf32_le_vec" + ;; + i860-*-sysv4* | i860-*-elf*) + targ_defvec=i860_elf32_vec + ;; + #ifdef BFD64 ia64*-*-freebsd* | ia64*-*-netbsd* | ia64*-*-linux-* | ia64*-*-elf* | ia64*-*-kfreebsd*-gnu) targ_defvec=ia64_elf64_le_vec diff --git a/bfd/configure b/bfd/configure index 1b829384c0c..50eace7af6c 100755 --- a/bfd/configure +++ b/bfd/configure @@ -15939,6 +15939,8 @@ do i386_pe_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pe_big_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pei_vec) tb="$tb pei-i386.lo peigen.lo $coff" ;; + i860_elf32_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + i860_elf32_le_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; iamcu_elf32_vec) tb="$tb elf32-i386.lo $elfxx_x86 elf32.lo $elf" ;; ia64_elf32_be_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; ia64_elf32_hpux_be_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index c30a75ba8b7..17424a933db 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -1,6 +1,7 @@ dnl Process this file with autoconf to produce a configure script. dnl dnl Copyright (C) 2012-2026 Free Software Foundation, Inc. +dnl Copyright (C) 2026 René Rebe dnl dnl This file is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -480,6 +481,8 @@ do i386_pe_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pe_big_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pei_vec) tb="$tb pei-i386.lo peigen.lo $coff" ;; + i860_elf32_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + i860_elf32_le_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; iamcu_elf32_vec) tb="$tb elf32-i386.lo $elfxx_x86 elf32.lo $elf" ;; ia64_elf32_be_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; ia64_elf32_hpux_be_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; diff --git a/bfd/cpu-i860.c b/bfd/cpu-i860.c new file mode 100644 index 00000000000..05427f14dbc --- /dev/null +++ b/bfd/cpu-i860.c @@ -0,0 +1,44 @@ +/* BFD support for the Intel 860 architecture. + Copyright (C) 1992-2018 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe + Created mostly by substituting "860" for "386" in cpu-i386.c + Harry Dolan , October 1995 + + 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 3 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_i860_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i860, + 0, /* only 1 machine */ + "i860", + "i860", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan, + bfd_arch_default_fill, + 0, + 0 /* Maximum offset of a reloc from the start of an insn. */ +}; diff --git a/bfd/elf32-i860.c b/bfd/elf32-i860.c new file mode 100644 index 00000000000..98a390ed397 --- /dev/null +++ b/bfd/elf32-i860.c @@ -0,0 +1,2601 @@ +/* Intel i860 specific support for 32-bit ELF. + Copyright (C) 1993-2018 Free Software Foundation, Inc. + + Full i860 support contributed by Jason Eckhardt . + Copyright (C) 2026 René Rebe + + 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 3 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/i860.h" + +/* special_function for R_860_PC26 relocation. */ +static bfd_reloc_status_type +i860_howto_pc26_reloc (bfd *abfd ATTRIBUTE_UNUSED, + arelent *reloc_entry, + asymbol *symbol, + void *data ATTRIBUTE_UNUSED, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_vma insn; + bfd_vma relocation; + bfd_byte *addr; + + if (output_bfd != NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Used elf32-mips.c as an example. */ + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + /* Adjust for PC-relative relocation. */ + relocation -= (input_section->output_section->vma + + input_section->output_offset + + reloc_entry->address + + 4); + + /* Check for target out of range. */ + if ((bfd_signed_vma)relocation > (0x3ffffff << 2) + || (bfd_signed_vma)relocation < (-0x4000000 * 4)) + return bfd_reloc_outofrange; + + addr = (bfd_byte *) data + reloc_entry->address; + insn = bfd_get_32 (abfd, addr); + + relocation >>= reloc_entry->howto->rightshift; + insn = (insn & ~reloc_entry->howto->dst_mask) + | (relocation & reloc_entry->howto->dst_mask); + + bfd_put_32 (abfd, (bfd_vma) insn, addr); + + return bfd_reloc_ok; +} + +/* special_function for R_860_PC16 relocation. */ +static bfd_reloc_status_type +i860_howto_pc16_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_vma insn; + bfd_vma relocation; + bfd_byte *addr; + + if (output_bfd != NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Used elf32-mips.c as an example. */ + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + /* Adjust for PC-relative relocation. */ + relocation -= (input_section->output_section->vma + + input_section->output_offset + + reloc_entry->address + + 4); + + /* Check for target out of range. */ + if ((bfd_signed_vma)relocation > (0x7fff << 2) + || (bfd_signed_vma)relocation < (-0x8000 * 4)) + return bfd_reloc_outofrange; + + addr = (bfd_byte *) data + reloc_entry->address; + insn = bfd_get_32 (abfd, addr); + + relocation >>= reloc_entry->howto->rightshift; + relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff)) + & reloc_entry->howto->dst_mask; + insn = (insn & ~reloc_entry->howto->dst_mask) | relocation; + + bfd_put_32 (abfd, (bfd_vma) insn, addr); + + return bfd_reloc_ok; +} + +/* special_function for R_860_HIGHADJ relocation. */ +static bfd_reloc_status_type +i860_howto_highadj_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_vma insn; + bfd_vma relocation; + bfd_byte *addr; + + if (output_bfd != NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Used elf32-mips.c as an example. */ + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + relocation += 0x8000; + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + addr = (bfd_byte *) data + reloc_entry->address; + insn = bfd_get_32 (abfd, addr); + + relocation = ((relocation >> 16) & 0xffff); + + insn = (insn & 0xffff0000) | relocation; + + bfd_put_32 (abfd, (bfd_vma) insn, addr); + + return bfd_reloc_ok; +} + +/* special_function for R_860_SPLITn relocations. */ +static bfd_reloc_status_type +i860_howto_splitn_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_vma insn; + bfd_vma relocation; + bfd_byte *addr; + + if (output_bfd != NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Used elf32-mips.c as an example. */ + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + addr = (bfd_byte *) data + reloc_entry->address; + insn = bfd_get_32 (abfd, addr); + + relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff)) + & reloc_entry->howto->dst_mask; + insn = (insn & ~reloc_entry->howto->dst_mask) | relocation; + + bfd_put_32 (abfd, (bfd_vma) insn, addr); + + return bfd_reloc_ok; +} + +/* This howto table is preliminary. */ +static reloc_howto_type elf32_i860_howto_table [] = +{ + /* This relocation does nothing. */ + HOWTO (R_860_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32-bit absolute relocation. */ + HOWTO (R_860_32, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_COPY, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_COPY", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_GLOB_DAT, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_GLOB_DAT", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_JUMP_SLOT, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_JUMP_SLOT", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_RELATIVE, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_RELATIVE", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 26-bit PC-relative relocation. */ + HOWTO (R_860_PC26, /* type */ + 2, /* rightshift */ + 4, /* size */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + i860_howto_pc26_reloc, /* special_function */ + "R_860_PC26", /* name */ + false, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_860_PLT26, /* type */ + 2, /* rightshift */ + 4, /* size */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_PLT26", /* name */ + false, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 16-bit PC-relative relocation. */ + HOWTO (R_860_PC16, /* type */ + 2, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + i860_howto_pc16_reloc, /* special_function */ + "R_860_PC16", /* name */ + false, /* partial_inplace */ + 0x1f07ff, /* src_mask */ + 0x1f07ff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_860_LOW0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOW0", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPLIT0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + i860_howto_splitn_reloc, /* special_function */ + "R_860_SPLIT0", /* name */ + false, /* partial_inplace */ + 0x1f07ff, /* src_mask */ + 0x1f07ff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOW1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOW1", /* name */ + false, /* partial_inplace */ + 0xfffe, /* src_mask */ + 0xfffe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPLIT1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + i860_howto_splitn_reloc, /* special_function */ + "R_860_SPLIT1", /* name */ + false, /* partial_inplace */ + 0x1f07fe, /* src_mask */ + 0x1f07fe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOW2, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOW2", /* name */ + false, /* partial_inplace */ + 0xfffc, /* src_mask */ + 0xfffc, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPLIT2, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + i860_howto_splitn_reloc, /* special_function */ + "R_860_SPLIT2", /* name */ + false, /* partial_inplace */ + 0x1f07fc, /* src_mask */ + 0x1f07fc, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOW3, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOW3", /* name */ + false, /* partial_inplace */ + 0xfff8, /* src_mask */ + 0xfff8, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOT0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOT0", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPGOT0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_SPGOT0", /* name */ + false, /* partial_inplace */ + 0x1f07ff, /* src_mask */ + 0x1f07ff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOT1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOT1", /* name */ + false, /* partial_inplace */ + 0xfffe, /* src_mask */ + 0xfffe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPGOT1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_SPGOT1", /* name */ + false, /* partial_inplace */ + 0x1f07fe, /* src_mask */ + 0x1f07fe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOTOFF0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOTOFF0", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPGOTOFF0, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_SPGOTOFF0", /* name */ + false, /* partial_inplace */ + 0x1f07ff, /* src_mask */ + 0x1f07ff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOTOFF1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOTOFF1", /* name */ + false, /* partial_inplace */ + 0xfffe, /* src_mask */ + 0xfffe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_SPGOTOFF1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_SPGOTOFF1", /* name */ + false, /* partial_inplace */ + 0x1f07fe, /* src_mask */ + 0x1f07fe, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOTOFF2, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOTOFF2", /* name */ + false, /* partial_inplace */ + 0xfffc, /* src_mask */ + 0xfffc, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOGOTOFF3, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOGOTOFF3", /* name */ + false, /* partial_inplace */ + 0xfff8, /* src_mask */ + 0xfff8, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_LOPC, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_LOPC", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HIGHADJ, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + i860_howto_highadj_reloc, /* special_function */ + "R_860_HIGHADJ", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HAGOT, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HAGOT", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HAGOTOFF, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HAGOTOFF", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HAPC, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HAPC", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HIGH, /* type */ + 16, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HIGH", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HIGOT, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HIGOT", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_HIGOTOFF, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_HIGOTOFF", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_860_TLS_DTPMOD32, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_DTPMOD32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_DTPOFF32, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_DTPOFF32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_TPOFF32, /* type */ + 0, /* rightshift */ + 4, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_TPOFF32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_GD_HI, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_GD_HI", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_GD_LO, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_GD_LO", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_IE_HA, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_IE_HA", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_IE_LO1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_IE_LO1", /* name */ + false, /* partial_inplace */ + 0xfffe, /* src_mask */ + 0xfffe, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_IE_ABS_HA, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_IE_ABS_HA", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_IE_ABS_LO1, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_IE_ABS_LO1", /* name */ + false, /* partial_inplace */ + 0xfffe, /* src_mask */ + 0xfffe, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_LE_HI, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_LE_HI", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_860_TLS_LE_LO, /* type */ + 0, /* rightshift */ + 4, /* size */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_860_TLS_LE_LO", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */}; + +static unsigned char elf_code_to_howto_index[R_860_max + 1]; + +static reloc_howto_type * +lookup_howto (unsigned int rtype) +{ + static int initialized = 0; + int i; + int howto_tbl_size = (int) (sizeof (elf32_i860_howto_table) + / sizeof (elf32_i860_howto_table[0])); + + if (! initialized) + { + initialized = 1; + memset (elf_code_to_howto_index, 0xff, + sizeof (elf_code_to_howto_index)); + for (i = 0; i < howto_tbl_size; i++) + elf_code_to_howto_index[elf32_i860_howto_table[i].type] = i; + } + + if (rtype >= R_860_max) + return NULL; + i = elf_code_to_howto_index[rtype]; + if (i >= howto_tbl_size) + return 0; + return elf32_i860_howto_table + i; +} + +/* Given a BFD reloc, return the matching HOWTO structure. */ +static reloc_howto_type * +elf32_i860_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int rtype; + + switch (code) + { + case BFD_RELOC_NONE: + rtype = R_860_NONE; + break; + case BFD_RELOC_32: + rtype = R_860_32; + break; + case BFD_RELOC_860_COPY: + rtype = R_860_COPY; + break; + case BFD_RELOC_860_GLOB_DAT: + rtype = R_860_GLOB_DAT; + break; + case BFD_RELOC_860_JUMP_SLOT: + rtype = R_860_JUMP_SLOT; + break; + case BFD_RELOC_860_RELATIVE: + rtype = R_860_RELATIVE; + break; + case BFD_RELOC_860_PC26: + rtype = R_860_PC26; + break; + case BFD_RELOC_860_PLT26: + rtype = R_860_PLT26; + break; + case BFD_RELOC_860_PC16: + rtype = R_860_PC16; + break; + case BFD_RELOC_860_LOW0: + rtype = R_860_LOW0; + break; + case BFD_RELOC_860_SPLIT0: + rtype = R_860_SPLIT0; + break; + case BFD_RELOC_860_LOW1: + rtype = R_860_LOW1; + break; + case BFD_RELOC_860_SPLIT1: + rtype = R_860_SPLIT1; + break; + case BFD_RELOC_860_LOW2: + rtype = R_860_LOW2; + break; + case BFD_RELOC_860_SPLIT2: + rtype = R_860_SPLIT2; + break; + case BFD_RELOC_860_LOW3: + rtype = R_860_LOW3; + break; + case BFD_RELOC_860_LOGOT0: + rtype = R_860_LOGOT0; + break; + case BFD_RELOC_860_SPGOT0: + rtype = R_860_SPGOT0; + break; + case BFD_RELOC_860_LOGOT1: + rtype = R_860_LOGOT1; + break; + case BFD_RELOC_860_SPGOT1: + rtype = R_860_SPGOT1; + break; + case BFD_RELOC_860_LOGOTOFF0: + rtype = R_860_LOGOTOFF0; + break; + case BFD_RELOC_860_SPGOTOFF0: + rtype = R_860_SPGOTOFF0; + break; + case BFD_RELOC_860_LOGOTOFF1: + rtype = R_860_LOGOTOFF1; + break; + case BFD_RELOC_860_SPGOTOFF1: + rtype = R_860_SPGOTOFF1; + break; + case BFD_RELOC_860_LOGOTOFF2: + rtype = R_860_LOGOTOFF2; + break; + case BFD_RELOC_860_LOGOTOFF3: + rtype = R_860_LOGOTOFF3; + break; + case BFD_RELOC_860_LOPC: + rtype = R_860_LOPC; + break; + case BFD_RELOC_860_HIGHADJ: + rtype = R_860_HIGHADJ; + break; + case BFD_RELOC_860_HAGOT: + rtype = R_860_HAGOT; + break; + case BFD_RELOC_860_HAGOTOFF: + rtype = R_860_HAGOTOFF; + break; + case BFD_RELOC_860_HAPC: + rtype = R_860_HAPC; + break; + case BFD_RELOC_860_HIGH: + rtype = R_860_HIGH; + break; + case BFD_RELOC_860_HIGOT: + rtype = R_860_HIGOT; + break; + case BFD_RELOC_860_HIGOTOFF: + rtype = R_860_HIGOTOFF; + break; + case BFD_RELOC_860_TLS_GD_HI: + rtype = R_860_TLS_GD_HI; + break; + case BFD_RELOC_860_TLS_GD_LO: + rtype = R_860_TLS_GD_LO; + break; + case BFD_RELOC_860_TLS_IE_HA: + rtype = R_860_TLS_IE_HA; + break; + case BFD_RELOC_860_TLS_IE_LO1: + rtype = R_860_TLS_IE_LO1; + break; + case BFD_RELOC_860_TLS_IE_ABS_HA: + rtype = R_860_TLS_IE_ABS_HA; + break; + case BFD_RELOC_860_TLS_IE_ABS_LO1: + rtype = R_860_TLS_IE_ABS_LO1; + break; + case BFD_RELOC_860_TLS_LE_HI: + rtype = R_860_TLS_LE_HI; + break; + case BFD_RELOC_860_TLS_LE_LO: + rtype = R_860_TLS_LE_LO; + break; + default: + rtype = 0; + break; + } + return lookup_howto (rtype); +} + +static reloc_howto_type * +elf32_i860_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (elf32_i860_howto_table) + / sizeof (elf32_i860_howto_table[0])); + i++) + if (elf32_i860_howto_table[i].name != NULL + && strcasecmp (elf32_i860_howto_table[i].name, r_name) == 0) + return &elf32_i860_howto_table[i]; + + return NULL; +} + +/* Given a ELF reloc, return the matching HOWTO structure. */ +static bool +elf32_i860_info_to_howto_rela (bfd *abfd, + arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc) +{ + unsigned int r_type = ELF32_R_TYPE (elf_reloc->r_info); + + bfd_reloc->howto = lookup_howto (r_type); + if (bfd_reloc->howto == NULL) + { + /* xgettext:c-format */ + _bfd_error_handler (_("%pB: unsupported relocation type %#x"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + return false; + } + return true; +} + +/* Specialized relocation handler for R_860_SPLITn. These relocations + involves a 16-bit field that is split into two contiguous parts. */ +static bfd_reloc_status_type +elf32_i860_relocate_splitn (bfd *input_bfd, + Elf_Internal_Rela *rello, + bfd_byte *contents, + bfd_vma value) +{ + bfd_vma insn; + reloc_howto_type *howto; + howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); + insn = bfd_get_32 (input_bfd, contents + rello->r_offset); + + /* Relocate. */ + value += rello->r_addend; + + /* Separate the fields and insert. */ + value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask; + insn = (insn & ~howto->dst_mask) | value; + + bfd_put_32 (input_bfd, insn, contents + rello->r_offset); + return bfd_reloc_ok; +} + +/* Specialized relocation handler for R_860_PC16. This relocation + involves a 16-bit, PC-relative field that is split into two contiguous + parts. */ +static bfd_reloc_status_type +elf32_i860_relocate_pc16 (bfd *input_bfd, + asection *input_section, + Elf_Internal_Rela *rello, + bfd_byte *contents, + bfd_vma value) +{ + bfd_vma insn; + reloc_howto_type *howto; + howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); + insn = bfd_get_32 (input_bfd, contents + rello->r_offset); + + /* Adjust for PC-relative relocation. */ + value -= (input_section->output_section->vma + + input_section->output_offset); + value -= rello->r_offset; + + /* Relocate. */ + value += rello->r_addend; + + /* Adjust the value by 4, then separate the fields and insert. */ + value -= 4; + if (((value & 0xffffffff) ^ 0x80000000) - 0x80000000 + 0x20000 >= 0x40000) + return bfd_reloc_overflow; + value >>= howto->rightshift; + value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask; + insn = (insn & ~howto->dst_mask) | value; + + bfd_put_32 (input_bfd, insn, contents + rello->r_offset); + return bfd_reloc_ok; + +} + +/* Specialized relocation handler for R_860_PC26. This relocation + involves a 26-bit, PC-relative field which must be adjusted by 4. */ +static bfd_reloc_status_type +elf32_i860_relocate_pc26 (bfd *input_bfd, + asection *input_section, + Elf_Internal_Rela *rello, + bfd_byte *contents, + bfd_vma value) +{ + bfd_vma insn; + reloc_howto_type *howto; + howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); + insn = bfd_get_32 (input_bfd, contents + rello->r_offset); + + /* Adjust for PC-relative relocation. */ + value -= (input_section->output_section->vma + + input_section->output_offset); + value -= rello->r_offset; + + /* Relocate. */ + value += rello->r_addend; + + /* Adjust value by 4 and insert the field. */ + value -= 4; + if (((value & 0xffffffff) ^ 0x80000000) - 0x80000000 + 0x8000000 >= 0x10000000) + return bfd_reloc_overflow; + value = (value >> howto->rightshift) & howto->dst_mask; + insn = (insn & ~howto->dst_mask) | value; + + bfd_put_32 (input_bfd, insn, contents + rello->r_offset); + return bfd_reloc_ok; + +} + +/* Specialized relocation handler for R_860_HIGHADJ. */ +static bfd_reloc_status_type +elf32_i860_relocate_highadj (bfd *input_bfd, + Elf_Internal_Rela *rel, + bfd_byte *contents, + bfd_vma value) +{ + bfd_vma insn; + + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + + value += rel->r_addend; + value += 0x8000; + value = ((value >> 16) & 0xffff); + + insn = (insn & 0xffff0000) | value; + + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + return bfd_reloc_ok; +} + +/* Perform a single relocation. By default we use the standard BFD + routines. However, we handle some specially. */ +static bfd_reloc_status_type +i860_final_link_relocate (reloc_howto_type *howto, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *rel, + bfd_vma relocation) +{ + return _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, relocation, + rel->r_addend); +} + +/* Dynamic linking. r15 holds the address of _GLOBAL_OFFSET_TABLE_ in PIC + code, but a PLT entry does not depend on it: it finds its slot PC relative + and uses r28 to keep the return address across the call reading the PC. + There is no lazy binding entry, the C library binds all slots at load. */ + +#define PLT_ENTRY_SIZE 32 +#define PLT_ENTRY_WORD0 0xa03c0000 /* mov %r1,%r28 */ +#define PLT_ENTRY_WORD1 0x6c000001 /* call .+8 */ +#define PLT_ENTRY_WORD2 0xa0000000 /* nop */ +#define PLT_ENTRY_WORD3 0xec1f0000 /* orh ha(slot-.),%r0,%r31 */ +#define PLT_ENTRY_WORD4 0x83ff0800 /* addu %r1,%r31,%r31 */ +#define PLT_ENTRY_WORD5 0x17ff0001 /* ld.l l(slot-.)(%r31),%r31 */ +#define PLT_ENTRY_WORD6 0x4000f800 /* bri %r31 */ +#define PLT_ENTRY_WORD7 0xa3810000 /* mov %r28,%r1 */ +#define PLT_PC_OFFSET 12 /* of the return address of the call */ + +#define GOT_HEADER_WORDS 3 +#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" + +struct elf_i860_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* Referenced by an absolute address in an instruction: a run time + relocation cannot fix that. */ + unsigned int has_insn_ref : 1; + + /* TLS accesses to this symbol, and their GOT entries. */ + unsigned char tls_mask; + bfd_vma tls_gd_got, tls_ie_got; +}; + +#define I860_TLS_GD 1 +#define I860_TLS_IE 2 + +/* Thread local storage, variant II: the block ends at the thread pointer in r30. */ +#define I860_LOCAL_GD(n) (n) /* in the local GOT array, after N entries */ +#define I860_LOCAL_IE(n) (2 * (n)) + +/* Whether a GOT entry of H needs a dynamic relocation with its symbol. */ +static int +i860_tls_dynsym (struct bfd_link_info *info, struct elf_link_hash_entry *h) +{ + return (h != NULL && h->dynindx != -1 + && elf_hash_table (info)->dynamic_sections_created + && !SYMBOL_REFERENCES_LOCAL (info, h)); +} + +#define i860_hash_table(p) elf_hash_table (p) + +static struct bfd_hash_entry * +i860_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, const char *string) +{ + struct elf_i860_link_hash_entry *ret + = (struct elf_i860_link_hash_entry *) entry; + + if (ret == NULL) + ret = bfd_hash_allocate (table, sizeof (struct elf_i860_link_hash_entry)); + if (ret == NULL) + return NULL; + + ret = ((struct elf_i860_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, + string)); + if (ret != NULL) + { + ret->has_insn_ref = 0; + ret->tls_mask = 0; + ret->tls_gd_got = ret->tls_ie_got = (bfd_vma) -1; + } + return (struct bfd_hash_entry *) ret; +} + +static struct bfd_link_hash_table * +i860_link_hash_table_create (bfd *abfd) +{ + struct elf_link_hash_table *ret = bfd_zmalloc (sizeof *ret); + + if (ret == NULL) + return NULL; + if (!_bfd_elf_link_hash_table_init (ret, abfd, i860_link_hash_newfunc, + sizeof (struct elf_i860_link_hash_entry))) + { + free (ret); + return NULL; + } + return &ret->root; +} + +static void +i860_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + ((struct elf_i860_link_hash_entry *) dir)->has_insn_ref + |= ((struct elf_i860_link_hash_entry *) ind)->has_insn_ref; + + ((struct elf_i860_link_hash_entry *) dir)->tls_mask + |= ((struct elf_i860_link_hash_entry *) ind)->tls_mask; + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +static bool +i860_create_got (bfd *abfd, struct elf_link_hash_table *htab, + struct bfd_link_info *info) +{ + if (htab->sgot != NULL) + return true; + if (htab->dynobj == NULL) + htab->dynobj = abfd; + return _bfd_elf_create_got_section (htab->dynobj, info); +} + +static bool +i860_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, + const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + struct elf_link_hash_table *htab = i860_hash_table (info); + asection *sreloc = NULL; + + if (bfd_link_relocatable (info) || (sec->flags & SEC_ALLOC) == 0) + return true; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h = NULL; + unsigned long r_symndx = ELF32_R_SYM (rel->r_info); + unsigned int r_type = ELF32_R_TYPE (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; + if (strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 + && !i860_create_got (abfd, htab, info)) + return false; + } + + switch (r_type) + { + case R_860_PC26: + case R_860_PLT26: + if (h != NULL) + { + h->needs_plt = 1; + h->plt.refcount += 1; + } + break; + + case R_860_TLS_GD_HI: + case R_860_TLS_GD_LO: + case R_860_TLS_IE_HA: + case R_860_TLS_IE_LO1: + case R_860_TLS_IE_ABS_HA: + case R_860_TLS_IE_ABS_LO1: + { + int gd = r_type == R_860_TLS_GD_HI || r_type == R_860_TLS_GD_LO; + + if ((r_type == R_860_TLS_IE_ABS_HA || r_type == R_860_TLS_IE_ABS_LO1) + && bfd_link_pic (info)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: relocation %s can not be used in position independent " + "output; recompile with -fPIC"), + abfd, lookup_howto (r_type)->name); + bfd_set_error (bfd_error_bad_value); + return 0; + } + if (!i860_create_got (abfd, htab, info)) + return 0; + if (!gd) + info->flags |= DF_STATIC_TLS; + if (h != NULL) + ((struct elf_i860_link_hash_entry *) h)->tls_mask + |= gd ? I860_TLS_GD : I860_TLS_IE; + else + { + unsigned int n = symtab_hdr->sh_info; + bfd_signed_vma *refs = elf_local_got_refcounts (abfd); + + if (refs == NULL) + { + refs = bfd_zalloc (abfd, 3 * n * sizeof (bfd_signed_vma)); + if (refs == NULL) + return 0; + elf_local_got_refcounts (abfd) = refs; + } + refs[(gd ? I860_LOCAL_GD (n) : I860_LOCAL_IE (n)) + r_symndx] = 1; + } + } + break; + + case R_860_TLS_LE_HI: + case R_860_TLS_LE_LO: + if (bfd_link_dll (info)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: relocation %s can not be used when making a shared " + "object; recompile with -fPIC"), + abfd, lookup_howto (r_type)->name); + bfd_set_error (bfd_error_bad_value); + return 0; + } + break; + + case R_860_LOGOT0: + case R_860_SPGOT0: + case R_860_LOGOT1: + case R_860_SPGOT1: + case R_860_HAGOT: + case R_860_HIGOT: + if (!i860_create_got (abfd, htab, info)) + return false; + if (h != NULL) + h->got.refcount += 1; + else + { + bfd_signed_vma *refs = elf_local_got_refcounts (abfd); + + if (refs == NULL) + { + /* also for the TLS entries of local symbols */ + refs = bfd_zalloc (abfd, (3 * symtab_hdr->sh_info + * sizeof (bfd_signed_vma))); + if (refs == NULL) + return false; + elf_local_got_refcounts (abfd) = refs; + } + refs[r_symndx] += 1; + } + break; + + case R_860_LOGOTOFF0: + case R_860_SPGOTOFF0: + case R_860_LOGOTOFF1: + case R_860_SPGOTOFF1: + case R_860_LOGOTOFF2: + case R_860_LOGOTOFF3: + case R_860_HAGOTOFF: + case R_860_HIGOTOFF: + if (!i860_create_got (abfd, htab, info)) + return false; + break; + + case R_860_HIGH: + case R_860_HIGHADJ: + case R_860_LOW0: + case R_860_LOW1: + case R_860_LOW2: + case R_860_LOW3: + case R_860_SPLIT0: + case R_860_SPLIT1: + case R_860_SPLIT2: + if (bfd_link_pic (info)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: relocation %s against `%s' can not be used when " + "making a shared object; recompile with -fPIC"), + abfd, lookup_howto (r_type)->name, + h != NULL ? h->root.root.string : "a local symbol"); + bfd_set_error (bfd_error_bad_value); + return false; + } + if (h != NULL) + { + h->non_got_ref = 1; + h->plt.refcount += 1; + h->pointer_equality_needed = 1; + ((struct elf_i860_link_hash_entry *) h)->has_insn_ref = 1; + } + break; + + case R_860_32: + if (h != NULL && !bfd_link_pic (info)) + { + h->non_got_ref = 1; + h->plt.refcount += 1; + h->pointer_equality_needed = 1; + } + + /* A shared object must copy these relocs, an executable may need + them for symbols of a shared object if it avoids a copy reloc. */ + if (bfd_link_pic (info) + || (h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular))) + { + struct elf_dyn_relocs *p; + struct elf_dyn_relocs **head; + + if (sreloc == NULL) + { + if (htab->dynobj == NULL) + htab->dynobj = abfd; + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, htab->dynobj, 2, abfd, true); + if (sreloc == NULL) + return false; + } + + if (h != NULL) + head = &h->dyn_relocs; + else + { + Elf_Internal_Sym *isym; + asection *s; + void *vpp; + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); + if (isym == NULL) + return false; + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + s = sec; + vpp = &elf_section_data (s)->local_dynrel; + head = (struct elf_dyn_relocs **) vpp; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + p = bfd_alloc (htab->dynobj, sizeof *p); + if (p == NULL) + return false; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + p->count += 1; + } + break; + + default: + break; + } + } + return true; +} + +static bool +i860_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_link_hash_table *htab = i860_hash_table (info); + asection *s, *srel; + + if (h->type == STT_FUNC || h->needs_plt) + { + /* A call to a symbol no dynamic object knows needs no PLT entry. */ + if (!bfd_link_pic (info) + && !h->def_dynamic + && !h->ref_dynamic + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined) + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + return true; + } + h->plt.offset = (bfd_vma) -1; + + if (h->is_weakalias) + { + struct elf_link_hash_entry *def = weakdef (h); + + BFD_ASSERT (def->root.type == bfd_link_hash_defined); + h->root.u.def.section = def->root.u.def.section; + h->root.u.def.value = def->root.u.def.value; + return true; + } + + /* Shared objects reach data of other objects through the GOT only. */ + if (bfd_link_pic (info) || !h->non_got_ref) + return true; + + /* Keep plain dynamic relocs instead of a copy reloc where possible. */ + if (info->nocopyreloc + || (!((struct elf_i860_link_hash_entry *) h)->has_insn_ref + && !_bfd_elf_readonly_dynrelocs (h))) + { + h->non_got_ref = 0; + return true; + } + + if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + { + s = htab->sdynrelro; + srel = htab->sreldynrelro; + } + else + { + s = htab->sdynbss; + srel = htab->srelbss; + } + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) + { + srel->size += sizeof (Elf32_External_Rela); + h->needs_copy = 1; + } + return _bfd_elf_adjust_dynamic_copy (info, h, s); +} + +static bool +i860_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct bfd_link_info *info = (struct bfd_link_info *) inf; + struct elf_link_hash_table *htab = i860_hash_table (info); + struct elf_dyn_relocs *p; + bool dyn = htab->dynamic_sections_created; + + if (h->root.type == bfd_link_hash_indirect) + return true; + + if (dyn && h->plt.refcount > 0) + { + if (h->dynindx == -1 && !h->forced_local + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h) + && !SYMBOL_CALLS_LOCAL (info, h)) + { + asection *s = htab->splt; + + h->plt.offset = s->size; + + /* The address of a function of a shared object taken in the + executable is its PLT entry, for pointer equality. */ + if (!bfd_link_pic (info) && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + s->size += PLT_ENTRY_SIZE; + htab->sgotplt->size += 4; + htab->srelplt->size += sizeof (Elf32_External_Rela); + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + if (((struct elf_i860_link_hash_entry *) h)->tls_mask) + { + struct elf_i860_link_hash_entry *th = (struct elf_i860_link_hash_entry *) h; + asection *sgot = elf_hash_table (info)->sgot; + asection *srelgot = elf_hash_table (info)->srelgot; + + if (h->dynindx == -1 && !h->forced_local + && elf_hash_table (info)->dynamic_sections_created + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return 0; + + if (th->tls_mask & I860_TLS_GD) + { + th->tls_gd_got = sgot->size; + sgot->size += 8; + if (i860_tls_dynsym (info, h)) + srelgot->size += 2 * sizeof (Elf32_External_Rela); + else if (bfd_link_pic (info)) + srelgot->size += sizeof (Elf32_External_Rela); + } + if (th->tls_mask & I860_TLS_IE) + { + th->tls_ie_got = sgot->size; + sgot->size += 4; + if (i860_tls_dynsym (info, h) || bfd_link_pic (info)) + srelgot->size += sizeof (Elf32_External_Rela); + } + } + + if (h->got.refcount > 0) + { + if (h->dynindx == -1 && !h->forced_local + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + h->got.offset = htab->sgot->size; + htab->sgot->size += 4; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) + htab->srelgot->size += sizeof (Elf32_External_Rela); + } + else + h->got.offset = (bfd_vma) -1; + + if (h->dyn_relocs == NULL) + return true; + + if (bfd_link_pic (info)) + { + if (h->root.type == bfd_link_hash_undefweak) + { + /* A RELATIVE reloc would turn the zero into the load address. */ + if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) + h->dyn_relocs = NULL; + else if (h->dynindx == -1 && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + } + else + { + /* Drop relocs of symbols that got a copy reloc or are not dynamic. */ + if (!h->non_got_ref + && ((h->def_dynamic && !h->def_regular) + || (dyn + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + if (h->dynindx == -1 && !h->forced_local + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + if (h->dynindx == -1) + h->dyn_relocs = NULL; + } + else + h->dyn_relocs = NULL; + } + + for (p = h->dyn_relocs; p != NULL; p = p->next) + elf_section_data (p->sec)->sreloc->size + += p->count * sizeof (Elf32_External_Rela); + return true; +} + +static bool +i860_late_size_sections (struct bfd_link_info *info) +{ + struct elf_link_hash_table *htab = i860_hash_table (info); + bfd *dynobj = htab->dynobj; + bool relocs = false; + asection *s; + bfd *ibfd; + + if (dynobj == NULL) + return true; + + if (htab->dynamic_sections_created + && bfd_link_executable (info) && !info->nointerp) + { + s = htab->interp; + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + s->alloced = 1; + } + + /* GOT entries and dynamic relocs of local symbols. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + bfd_signed_vma *local_got, *end_local_got; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf_dyn_relocs *p; + + for (p = ((struct elf_dyn_relocs *) + elf_section_data (s)->local_dynrel); + p != NULL; p = p->next) + if (!(!bfd_is_abs_section (p->sec) + && bfd_is_abs_section (p->sec->output_section)) + && p->count != 0) + { + elf_section_data (p->sec)->sreloc->size + += p->count * sizeof (Elf32_External_Rela); + if ((p->sec->output_section->flags & SEC_READONLY) != 0) + info->flags |= DF_TEXTREL; + } + } + + local_got = elf_local_got_refcounts (ibfd); + if (local_got == NULL) + continue; + + end_local_got = local_got + elf_tdata (ibfd)->symtab_hdr.sh_info; + for (; local_got < end_local_got; ++local_got) + if (*local_got > 0) + { + *local_got = htab->sgot->size; + htab->sgot->size += 4; + if (bfd_link_pic (info)) + htab->srelgot->size += sizeof (Elf32_External_Rela); + } + else + *local_got = (bfd_vma) -1; + /* TLS entries of local symbols, in the same array after the GOT counts. */ + { + unsigned int n = elf_tdata (ibfd)->symtab_hdr.sh_info, i; + bfd_signed_vma *refs = elf_local_got_refcounts (ibfd); + for (i = 0; i < n; i++) + { + bfd_signed_vma *g = &refs[I860_LOCAL_GD (n) + i]; + bfd_signed_vma *e = &refs[I860_LOCAL_IE (n) + i]; + if (*g > 0) + { + *g = elf_hash_table (info)->sgot->size; + elf_hash_table (info)->sgot->size += 8; + if (bfd_link_pic (info)) + elf_hash_table (info)->srelgot->size += sizeof (Elf32_External_Rela); + } + else + *g = (bfd_vma) -1; + if (*e > 0) + { + *e = elf_hash_table (info)->sgot->size; + elf_hash_table (info)->sgot->size += 4; + if (bfd_link_pic (info)) + elf_hash_table (info)->srelgot->size += sizeof (Elf32_External_Rela); + } + else + *e = (bfd_vma) -1; + } + } + } + + elf_link_hash_traverse (htab, i860_allocate_dynrelocs, info); + + for (s = dynobj->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->splt || s == htab->sgot + || s == htab->sgotplt || s == htab->sdynbss + || s == htab->sdynrelro) + ; + else if (startswith (bfd_section_name (s), ".rela")) + { + if (s->size != 0 && s != htab->srelplt) + relocs = true; + s->reloc_count = 0; + } + else + continue; + + if (s->size == 0) + { + s->flags |= SEC_EXCLUDE; + continue; + } + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + s->contents = bfd_zalloc (dynobj, s->size); + if (s->contents == NULL) + return false; + s->alloced = 1; + } + + return _bfd_elf_add_dynamic_tags (info, relocs); +} + +static bfd_vma +i860_section_addr (asection *s) +{ + return s->output_section->vma + s->output_offset; +} + +static void +i860_append_rela (bfd *output_bfd, asection *srel, Elf_Internal_Rela *rela) +{ + bfd_elf32_swap_reloca_out (output_bfd, rela, + srel->contents + + srel->reloc_count * sizeof (Elf32_External_Rela)); + srel->reloc_count++; +} + +static bool +i860_finish_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + bfd *output_bfd = info->output_bfd; + struct elf_link_hash_table *htab = i860_hash_table (info); + Elf_Internal_Rela rela; + + if (h->plt.offset != (bfd_vma) -1) + { + asection *splt = htab->splt; + asection *sgotplt = htab->sgotplt; + bfd_byte *ent = splt->contents + h->plt.offset; + bfd_vma index = h->plt.offset / PLT_ENTRY_SIZE; + bfd_vma got_offset = (index + GOT_HEADER_WORDS) * 4; + bfd_vma slot = i860_section_addr (sgotplt) + got_offset; + bfd_vma rel = slot - (i860_section_addr (splt) + h->plt.offset + + PLT_PC_OFFSET); + + BFD_ASSERT (h->dynindx != -1); + + bfd_put_32 (output_bfd, PLT_ENTRY_WORD0, ent); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD1, ent + 4); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD2, ent + 8); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD3 | (((rel + 0x8000) >> 16) & 0xffff), + ent + 12); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD4, ent + 16); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD5 | (rel & 0xfffc), ent + 20); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD6, ent + 24); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD7, ent + 28); + + rela.r_offset = slot; + rela.r_info = ELF32_R_INFO (h->dynindx, R_860_JUMP_SLOT); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + htab->srelplt->contents + + index * sizeof (Elf32_External_Rela)); + + if (!h->def_regular) + { + /* A zero value hides the entry from the search for the definition + unless its address has to be the canonical function address. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; + } + } + + if (h->got.offset != (bfd_vma) -1) + { + asection *sgot = htab->sgot; + bool local = (bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h)); + + rela.r_offset = i860_section_addr (sgot) + (h->got.offset & ~(bfd_vma) 1); + if (local && h->root.type != bfd_link_hash_undefweak) + { + rela.r_info = ELF32_R_INFO (0, R_860_RELATIVE); + rela.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + i860_append_rela (output_bfd, htab->srelgot, &rela); + } + else if (!local) + { + bfd_put_32 (output_bfd, 0, + sgot->contents + (h->got.offset & ~(bfd_vma) 1)); + rela.r_info = ELF32_R_INFO (h->dynindx, R_860_GLOB_DAT); + rela.r_addend = 0; + i860_append_rela (output_bfd, htab->srelgot, &rela); + } + } + + if (h->needs_copy) + { + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + rela.r_offset = (h->root.u.def.value + + i860_section_addr (h->root.u.def.section)); + rela.r_info = ELF32_R_INFO (h->dynindx, R_860_COPY); + rela.r_addend = 0; + i860_append_rela (output_bfd, + (h->root.u.def.section == htab->sdynrelro + ? htab->sreldynrelro : htab->srelbss), + &rela); + } + + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 || h == htab->hgot) + sym->st_shndx = SHN_ABS; + + return true; +} + +static bool +i860_finish_dynamic_sections (struct bfd_link_info *info, + bfd_byte *buf ATTRIBUTE_UNUSED) +{ + bfd *output_bfd = info->output_bfd; + struct elf_link_hash_table *htab = i860_hash_table (info); + bfd *dynobj = htab->dynobj; + asection *sgotplt = htab->sgotplt; + asection *sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (htab->dynamic_sections_created) + { + Elf32_External_Dyn *dyncon = (Elf32_External_Dyn *) sdyn->contents; + Elf32_External_Dyn *dynconend + = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); + + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + switch (dyn.d_tag) + { + case DT_PLTGOT: + dyn.d_un.d_ptr = i860_section_addr (sgotplt); + break; + case DT_JMPREL: + dyn.d_un.d_ptr = i860_section_addr (htab->srelplt); + break; + case DT_PLTRELSZ: + dyn.d_un.d_val = htab->srelplt->size; + break; + default: + continue; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + if (htab->splt != NULL && htab->splt->size > 0) + elf_section_data (htab->splt->output_section)->this_hdr.sh_entsize + = PLT_ENTRY_SIZE; + } + + if (sgotplt != NULL && sgotplt->size > 0) + { + bfd_put_32 (output_bfd, + sdyn != NULL ? i860_section_addr (sdyn) : (bfd_vma) 0, + sgotplt->contents); + elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4; + } + if (htab->sgot != NULL && htab->sgot->size > 0) + elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4; + + return true; +} + +static enum elf_reloc_type_class +i860_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_860_RELATIVE: + return reloc_class_relative; + case R_860_JUMP_SLOT: + return reloc_class_plt; + case R_860_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +static bfd_vma +i860_tpoff (struct bfd_link_info *info, bfd_vma address) +{ + asection *tls = elf_hash_table (info)->tls_sec; + + if (tls == NULL) + return 0; + return address - (tls->vma + BFD_ALIGN (elf_hash_table (info)->tls_size, + (bfd_vma) 1 << tls->alignment_power)); +} + +/* The address of the GOT entries at *OFFP, filled on the first use. */ +static bfd_vma +i860_tls_got_entry (bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, bfd_vma *offp, + bfd_vma relocation, int gd) +{ + asection *sgot = elf_hash_table (info)->sgot; + asection *tls = elf_hash_table (info)->tls_sec; + bfd_vma off = *offp & ~(bfd_vma) 1; + bfd_vma addr = i860_section_addr (sgot) + off; + bfd_vma dtpoff = tls != NULL ? relocation - tls->vma : 0; + + BFD_ASSERT (*offp != (bfd_vma) -1); + if ((*offp & 1) == 0) + { + int dynsym = i860_tls_dynsym (info, h); + unsigned long sym = dynsym ? h->dynindx : 0; + Elf_Internal_Rela rela; + + *offp |= 1; + rela.r_offset = addr; + rela.r_addend = 0; + if (gd) + { + /* an executable is module 1 */ + bfd_put_32 (output_bfd, dynsym || bfd_link_pic (info) ? 0 : 1, + sgot->contents + off); + bfd_put_32 (output_bfd, dynsym ? 0 : dtpoff, sgot->contents + off + 4); + if (dynsym || bfd_link_pic (info)) + { + rela.r_info = ELF32_R_INFO (sym, R_860_TLS_DTPMOD32); + i860_append_rela (output_bfd, elf_hash_table (info)->srelgot, &rela); + } + if (dynsym) + { + rela.r_offset = addr + 4; + rela.r_info = ELF32_R_INFO (sym, R_860_TLS_DTPOFF32); + i860_append_rela (output_bfd, elf_hash_table (info)->srelgot, &rela); + } + } + else + { + bfd_put_32 (output_bfd, dynsym ? 0 : i860_tpoff (info, relocation), + sgot->contents + off); + if (dynsym || bfd_link_pic (info)) + { + rela.r_info = ELF32_R_INFO (sym, R_860_TLS_TPOFF32); + rela.r_addend = dynsym ? 0 : dtpoff; + i860_append_rela (output_bfd, elf_hash_table (info)->srelgot, &rela); + } + } + } + return addr; +} + +/* Insert VALUE into a GOT, GOT offset or PC relative immediate field. */ +static bfd_reloc_status_type +i860_relocate_pic_field (bfd *abfd, int r_type, bfd_byte *where, bfd_vma value) +{ + bfd_vma insn = bfd_get_32 (abfd, where); + bfd_vma mask = 0xffff; + bool split = false; + + switch (r_type) + { + case R_860_HAGOT: + case R_860_HAGOTOFF: + case R_860_HAPC: + case R_860_TLS_IE_HA: + case R_860_TLS_IE_ABS_HA: + value = (value + 0x8000) >> 16; + break; + case R_860_HIGOT: + case R_860_HIGOTOFF: + case R_860_TLS_GD_HI: + case R_860_TLS_LE_HI: + value >>= 16; + break; + case R_860_LOGOT0: + case R_860_LOGOTOFF0: + case R_860_LOPC: + case R_860_TLS_GD_LO: + case R_860_TLS_LE_LO: + break; + case R_860_LOGOT1: + case R_860_LOGOTOFF1: + case R_860_TLS_IE_LO1: + case R_860_TLS_IE_ABS_LO1: + mask = 0xfffe; + break; + case R_860_LOGOTOFF2: + mask = 0xfffc; + break; + case R_860_LOGOTOFF3: + mask = 0xfff8; + break; + case R_860_SPGOT1: + case R_860_SPGOTOFF1: + mask = 0xfffe; + split = true; + break; + case R_860_SPGOT0: + case R_860_SPGOTOFF0: + split = true; + break; + default: + return bfd_reloc_notsupported; + } + + value &= mask; + if (split) + { + value = ((value & 0xf800) << 5) | (value & 0x7ff); + mask = ((mask & 0xf800) << 5) | (mask & 0x7ff); + } + bfd_put_32 (abfd, (insn & ~mask) | value, where); + return bfd_reloc_ok; +} + +/* The GOT entry of a symbol, relative to _GLOBAL_OFFSET_TABLE_. Fills the + entry unless the dynamic linker does. */ +static bfd_vma +i860_got_offset (bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_table *htab, + struct elf_link_hash_entry *h, bfd_vma *local_got, + bfd_vma relocation) +{ + asection *sgot = htab->sgot; + bfd_vma off; + + if (h != NULL) + { + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) -1); + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (htab->dynamic_sections_created, + bfd_link_pic (info), h) + || (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))) + { + if ((off & 1) == 0) + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + h->got.offset |= 1; + } + off &= ~(bfd_vma) 1; + } + } + else + { + off = *local_got; + BFD_ASSERT (off != (bfd_vma) -1); + if ((off & 1) == 0) + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + if (bfd_link_pic (info)) + { + Elf_Internal_Rela rela; + + rela.r_offset = i860_section_addr (sgot) + off; + rela.r_info = ELF32_R_INFO (0, R_860_RELATIVE); + rela.r_addend = relocation; + i860_append_rela (output_bfd, htab->srelgot, &rela); + } + *local_got |= 1; + } + off &= ~(bfd_vma) 1; + } + return (i860_section_addr (sgot) + off + - (htab->hgot->root.u.def.value + + i860_section_addr (htab->hgot->root.u.def.section))); +} + +static int +i860_relocate_section (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 *output_bfd = info->output_bfd; + struct elf_link_hash_table *htab = i860_hash_table (info); + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); + bfd_vma *local_got = elf_local_got_offsets (input_bfd); + asection *sreloc = elf_section_data (input_section)->sreloc; + Elf_Internal_Rela *relend = relocs + input_section->reloc_count; + Elf_Internal_Rela *rel; + + for (rel = relocs; rel < relend; rel++) + { + reloc_howto_type *howto; + unsigned long r_symndx = ELF32_R_SYM (rel->r_info); + int r_type = ELF32_R_TYPE (rel->r_info); + Elf_Internal_Sym *sym = NULL; + asection *sec = NULL; + struct elf_link_hash_entry *h = NULL; + bfd_vma relocation; + bfd_reloc_status_type r; + const char *name = NULL; + bfd_vma pc; + + howto = lookup_howto ((unsigned) r_type); + if (howto == NULL) + { + /* xgettext:c-format */ + _bfd_error_handler (_("%pB: unsupported relocation type %#x"), + input_bfd, r_type); + bfd_set_error (bfd_error_bad_value); + return 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); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (sec) : name; + } + else + { + bool unresolved_reloc, warned, ignored; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned, ignored); + name = h->root.root.string; + } + + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, R_860_NONE, + howto, 0, contents); + + if (bfd_link_relocatable (info)) + continue; + + pc = i860_section_addr (input_section) + rel->r_offset; + + switch (r_type) + { + default: + r = i860_final_link_relocate (howto, input_bfd, input_section, + contents, rel, relocation); + break; + + case R_860_32: + if (r_symndx != STN_UNDEF + && (input_section->flags & SEC_ALLOC) != 0 + && ((bfd_link_pic (info) + && (h == NULL || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) + || (!bfd_link_pic (info) + && h != NULL + && h->dynindx != -1 + && !h->non_got_ref + && ((h->def_dynamic && !h->def_regular) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + Elf_Internal_Rela outrel; + bfd_vma off = _bfd_elf_section_offset (output_bfd, info, + input_section, + rel->r_offset); + + BFD_ASSERT (sreloc != NULL); + memset (&outrel, 0, sizeof outrel); + if (off != (bfd_vma) -1 && off != (bfd_vma) -2) + { + outrel.r_offset = off + i860_section_addr (input_section); + if (h != NULL && h->dynindx != -1 + && !(bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h))) + { + outrel.r_info = ELF32_R_INFO (h->dynindx, R_860_32); + outrel.r_addend = rel->r_addend; + } + else + { + outrel.r_info = ELF32_R_INFO (0, R_860_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + } + i860_append_rela (output_bfd, sreloc, &outrel); + /* -2: .eh_frame made pc relative, the value goes in place. */ + if (off != (bfd_vma) -2) + continue; + } + r = i860_final_link_relocate (howto, input_bfd, input_section, + contents, rel, relocation); + break; + + case R_860_HIGHADJ: + r = elf32_i860_relocate_highadj (input_bfd, rel, contents, + relocation); + break; + + case R_860_PC16: + r = elf32_i860_relocate_pc16 (input_bfd, input_section, rel, + contents, relocation); + break; + + case R_860_PC26: + case R_860_PLT26: + if (h != NULL && h->plt.offset != (bfd_vma) -1 + && htab->splt != NULL) + relocation = (i860_section_addr (htab->splt) + h->plt.offset); + r = elf32_i860_relocate_pc26 (input_bfd, input_section, rel, + contents, relocation); + break; + + case R_860_SPLIT0: + case R_860_SPLIT1: + case R_860_SPLIT2: + r = elf32_i860_relocate_splitn (input_bfd, rel, contents, + relocation); + break; + + case R_860_LOGOT0: + case R_860_SPGOT0: + case R_860_LOGOT1: + case R_860_SPGOT1: + case R_860_HAGOT: + case R_860_HIGOT: + relocation = i860_got_offset (output_bfd, info, htab, h, + (h == NULL && local_got != NULL + ? &local_got[r_symndx] : NULL), + relocation + (h == NULL ? 0 : rel->r_addend)); + r = i860_relocate_pic_field (input_bfd, r_type, + contents + rel->r_offset, relocation); + break; + + case R_860_LOGOTOFF0: + case R_860_SPGOTOFF0: + case R_860_LOGOTOFF1: + case R_860_SPGOTOFF1: + case R_860_LOGOTOFF2: + case R_860_LOGOTOFF3: + case R_860_HAGOTOFF: + case R_860_HIGOTOFF: + relocation += (rel->r_addend + - (htab->hgot->root.u.def.value + + i860_section_addr + (htab->hgot->root.u.def.section))); + r = i860_relocate_pic_field (input_bfd, r_type, + contents + rel->r_offset, relocation); + break; + + case R_860_LOPC: + case R_860_HAPC: + if (h != NULL && bfd_link_pic (info) + && h != htab->hgot + && !SYMBOL_REFERENCES_LOCAL (info, h)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: PC relative relocation %s against preemptible " + "symbol `%s'"), + input_bfd, howto->name, name); + bfd_set_error (bfd_error_bad_value); + return false; + } + r = i860_relocate_pic_field (input_bfd, r_type, + contents + rel->r_offset, + relocation + rel->r_addend - pc); + break; + + case R_860_TLS_GD_HI: + case R_860_TLS_GD_LO: + case R_860_TLS_IE_HA: + case R_860_TLS_IE_LO1: + case R_860_TLS_IE_ABS_HA: + case R_860_TLS_IE_ABS_LO1: + { + int gd = r_type == R_860_TLS_GD_HI || r_type == R_860_TLS_GD_LO; + int abs = r_type == R_860_TLS_IE_ABS_HA || r_type == R_860_TLS_IE_ABS_LO1; + struct elf_i860_link_hash_entry *th = (struct elf_i860_link_hash_entry *) h; + unsigned int n = symtab_hdr->sh_info; + bfd_vma *offp; + + if (th != NULL) + offp = gd ? &th->tls_gd_got : &th->tls_ie_got; + else + offp = &local_got[(gd ? I860_LOCAL_GD (n) : I860_LOCAL_IE (n)) + r_symndx]; + relocation = i860_tls_got_entry (output_bfd, info, h, offp, relocation, gd); + if (!abs) + relocation -= (elf_hash_table (info)->hgot->root.u.def.value + + i860_section_addr + (elf_hash_table (info)->hgot->root.u.def.section)); + r = i860_relocate_pic_field (input_bfd, r_type, + contents + rel->r_offset, relocation); + } + break; + + case R_860_TLS_LE_HI: + case R_860_TLS_LE_LO: + r = i860_relocate_pic_field (input_bfd, r_type, contents + rel->r_offset, + i860_tpoff (info, relocation) + rel->r_addend); + break; + + /* Output only relocations. */ + case R_860_TLS_DTPMOD32: + case R_860_TLS_DTPOFF32: + case R_860_TLS_TPOFF32: + case R_860_COPY: + case R_860_GLOB_DAT: + case R_860_JUMP_SLOT: + case R_860_RELATIVE: + r = bfd_reloc_notsupported; + break; + } + + if (r != bfd_reloc_ok) + { + const char *msg = NULL; + + switch (r) + { + case bfd_reloc_overflow: + (*info->callbacks->reloc_overflow) + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); + break; + case bfd_reloc_undefined: + (*info->callbacks->undefined_symbol) + (info, name, input_bfd, input_section, rel->r_offset, true); + break; + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + default: + msg = _("internal error: unknown error"); + break; + } + if (msg) + (*info->callbacks->warning) (info, msg, name, input_bfd, + input_section, rel->r_offset); + } + } + return true; +} + +/* Return whether a symbol name implies a local label. SVR4/860 compilers + generate labels of the form ".ep.function_name" to denote the end of a + function prolog. These should be local. + ??? Do any other SVR4 compilers have this convention? If so, this should + be added to the generic routine. */ +static bool +elf32_i860_is_local_label_name (bfd *abfd, const char *name) +{ + if (name[0] == '.' && name[1] == 'e' && name[2] == 'p' && name[3] == '.') + return true; + + return _bfd_elf_is_local_label_name (abfd, name); +} + +#define TARGET_BIG_SYM i860_elf32_vec +#define TARGET_BIG_NAME "elf32-i860" +#define TARGET_LITTLE_SYM i860_elf32_le_vec +#define TARGET_LITTLE_NAME "elf32-i860-little" +#define ELF_ARCH bfd_arch_i860 +#define ELF_MACHINE_CODE EM_860 +#define ELF_MAXPAGESIZE 4096 + +#define elf_backend_rela_normal 1 +#define elf_info_to_howto_rel NULL +#define elf_info_to_howto elf32_i860_info_to_howto_rela +#define elf_backend_relocate_section i860_relocate_section +#define elf_backend_check_relocs i860_check_relocs +#define elf_backend_can_gc_sections 1 +#define elf_backend_can_refcount 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_want_got_plt 1 +#define elf_backend_want_plt_sym 0 +#define elf_backend_got_header_size (GOT_HEADER_WORDS * 4) +#define elf_backend_dtrel_excludes_plt 1 +#define elf_backend_want_dynrelro 1 +#define elf_backend_reloc_type_class i860_reloc_type_class +#define elf_backend_copy_indirect_symbol i860_copy_indirect_symbol +#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections +#define elf_backend_adjust_dynamic_symbol i860_adjust_dynamic_symbol +#define elf_backend_late_size_sections i860_late_size_sections +#define elf_backend_finish_dynamic_symbol i860_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections i860_finish_dynamic_sections +#define bfd_elf32_bfd_link_hash_table_create i860_link_hash_table_create +#define bfd_elf32_bfd_reloc_type_lookup elf32_i860_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup elf32_i860_reloc_name_lookup +#define bfd_elf32_bfd_is_local_label_name elf32_i860_is_local_label_name + +#include "elf32-target.h" diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 27bc0875cf6..6862cdb6059 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2652,6 +2652,46 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_CRIS_16_TPREL", "BFD_RELOC_CRIS_DTPMOD", "BFD_RELOC_CRIS_32_IE", + "BFD_RELOC_860_COPY", + "BFD_RELOC_860_GLOB_DAT", + "BFD_RELOC_860_JUMP_SLOT", + "BFD_RELOC_860_RELATIVE", + "BFD_RELOC_860_PC26", + "BFD_RELOC_860_PLT26", + "BFD_RELOC_860_PC16", + "BFD_RELOC_860_LOW0", + "BFD_RELOC_860_SPLIT0", + "BFD_RELOC_860_LOW1", + "BFD_RELOC_860_SPLIT1", + "BFD_RELOC_860_LOW2", + "BFD_RELOC_860_SPLIT2", + "BFD_RELOC_860_LOW3", + "BFD_RELOC_860_LOGOT0", + "BFD_RELOC_860_SPGOT0", + "BFD_RELOC_860_LOGOT1", + "BFD_RELOC_860_SPGOT1", + "BFD_RELOC_860_LOGOTOFF0", + "BFD_RELOC_860_SPGOTOFF0", + "BFD_RELOC_860_LOGOTOFF1", + "BFD_RELOC_860_SPGOTOFF1", + "BFD_RELOC_860_LOGOTOFF2", + "BFD_RELOC_860_LOGOTOFF3", + "BFD_RELOC_860_LOPC", + "BFD_RELOC_860_HIGHADJ", + "BFD_RELOC_860_HAGOT", + "BFD_RELOC_860_HAGOTOFF", + "BFD_RELOC_860_HAPC", + "BFD_RELOC_860_HIGH", + "BFD_RELOC_860_HIGOT", + "BFD_RELOC_860_HIGOTOFF", + "BFD_RELOC_860_TLS_GD_HI", + "BFD_RELOC_860_TLS_GD_LO", + "BFD_RELOC_860_TLS_IE_HA", + "BFD_RELOC_860_TLS_IE_LO1", + "BFD_RELOC_860_TLS_IE_ABS_HA", + "BFD_RELOC_860_TLS_IE_ABS_LO1", + "BFD_RELOC_860_TLS_LE_HI", + "BFD_RELOC_860_TLS_LE_LO", "BFD_RELOC_OR1K_REL_26", "BFD_RELOC_OR1K_SLO16", "BFD_RELOC_OR1K_PCREL_PG21", diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in index 40632924764..9cd44ca4869 100644 --- a/bfd/po/SRC-POTFILES.in +++ b/bfd/po/SRC-POTFILES.in @@ -64,6 +64,7 @@ cpu-h8300.c cpu-h8300.h cpu-hppa.c cpu-i386.c +cpu-i860.c cpu-ia64.c cpu-iamcu.c cpu-ip2k.c @@ -176,6 +177,7 @@ elf32-h8300.c elf32-hppa.c elf32-hppa.h elf32-i386.c +elf32-i860.c elf32-ip2k.c elf32-iq2000.c elf32-lm32.c diff --git a/bfd/reloc.c b/bfd/reloc.c index 6b9e00da5d6..9dab970c2b7 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -1,5 +1,6 @@ /* BFD support for handling relocation entries. Copyright (C) 1990-2026 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -5636,6 +5637,89 @@ ENUMX ENUMDOC Relocs used in TLS code for CRIS. +ENUM + BFD_RELOC_860_COPY +ENUMX + BFD_RELOC_860_GLOB_DAT +ENUMX + BFD_RELOC_860_JUMP_SLOT +ENUMX + BFD_RELOC_860_RELATIVE +ENUMX + BFD_RELOC_860_PC26 +ENUMX + BFD_RELOC_860_PLT26 +ENUMX + BFD_RELOC_860_PC16 +ENUMX + BFD_RELOC_860_LOW0 +ENUMX + BFD_RELOC_860_SPLIT0 +ENUMX + BFD_RELOC_860_LOW1 +ENUMX + BFD_RELOC_860_SPLIT1 +ENUMX + BFD_RELOC_860_LOW2 +ENUMX + BFD_RELOC_860_SPLIT2 +ENUMX + BFD_RELOC_860_LOW3 +ENUMX + BFD_RELOC_860_LOGOT0 +ENUMX + BFD_RELOC_860_SPGOT0 +ENUMX + BFD_RELOC_860_LOGOT1 +ENUMX + BFD_RELOC_860_SPGOT1 +ENUMX + BFD_RELOC_860_LOGOTOFF0 +ENUMX + BFD_RELOC_860_SPGOTOFF0 +ENUMX + BFD_RELOC_860_LOGOTOFF1 +ENUMX + BFD_RELOC_860_SPGOTOFF1 +ENUMX + BFD_RELOC_860_LOGOTOFF2 +ENUMX + BFD_RELOC_860_LOGOTOFF3 +ENUMX + BFD_RELOC_860_LOPC +ENUMX + BFD_RELOC_860_HIGHADJ +ENUMX + BFD_RELOC_860_HAGOT +ENUMX + BFD_RELOC_860_HAGOTOFF +ENUMX + BFD_RELOC_860_HAPC +ENUMX + BFD_RELOC_860_HIGH +ENUMX + BFD_RELOC_860_HIGOT +ENUMX + BFD_RELOC_860_HIGOTOFF +ENUMX + BFD_RELOC_860_TLS_GD_HI +ENUMX + BFD_RELOC_860_TLS_GD_LO +ENUMX + BFD_RELOC_860_TLS_IE_HA +ENUMX + BFD_RELOC_860_TLS_IE_LO1 +ENUMX + BFD_RELOC_860_TLS_IE_ABS_HA +ENUMX + BFD_RELOC_860_TLS_IE_ABS_LO1 +ENUMX + BFD_RELOC_860_TLS_LE_HI +ENUMX + BFD_RELOC_860_TLS_LE_LO +ENUMDOC + Intel i860 Relocations. + ENUM BFD_RELOC_OR1K_REL_26 ENUMX diff --git a/bfd/targets.c b/bfd/targets.c index fcf650410dc..bf83e23d551 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -1,5 +1,6 @@ /* Generic target-file-type support for the BFD library. Copyright (C) 1990-2026 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -758,6 +759,8 @@ extern const bfd_target i386_msdos_vec; extern const bfd_target i386_pe_vec; extern const bfd_target i386_pe_big_vec; extern const bfd_target i386_pei_vec; +extern const bfd_target i860_elf32_vec; +extern const bfd_target i860_elf32_le_vec; extern const bfd_target iamcu_elf32_vec; extern const bfd_target ia64_elf32_be_vec; extern const bfd_target ia64_elf32_hpux_be_vec; @@ -1104,6 +1107,8 @@ static const bfd_target * const _bfd_target_vector[] = &i386_pe_big_vec, &i386_pei_vec, + &i860_elf32_vec, + &i860_elf32_le_vec, &iamcu_elf32_vec, #ifdef BFD64 diff --git a/gas/Makefile.am b/gas/Makefile.am index 9f90a1de50e..46944192eb2 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to generate Makefile.in # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -164,6 +165,7 @@ TARGET_CPU_CFILES = \ config/tc-hppa.c \ config/tc-ia64.c \ config/tc-i386.c \ + config/tc-i860.c \ config/tc-ip2k.c \ config/tc-iq2000.c \ config/tc-kvx.c \ @@ -239,6 +241,7 @@ TARGET_CPU_HFILES = \ config/tc-hppa.h \ config/tc-ia64.h \ config/tc-i386.h \ + config/tc-i860.h \ config/tc-ip2k.h \ config/tc-iq2000.h \ config/tc-kvx.h \ diff --git a/gas/Makefile.in b/gas/Makefile.in index b2bb505cc69..38f76175d6c 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -666,6 +666,7 @@ TARGET_CPU_CFILES = \ config/tc-hppa.c \ config/tc-ia64.c \ config/tc-i386.c \ + config/tc-i860.c \ config/tc-ip2k.c \ config/tc-iq2000.c \ config/tc-kvx.c \ @@ -741,6 +742,7 @@ TARGET_CPU_HFILES = \ config/tc-hppa.h \ config/tc-ia64.h \ config/tc-i386.h \ + config/tc-i860.h \ config/tc-ip2k.h \ config/tc-iq2000.h \ config/tc-kvx.h \ @@ -982,6 +984,7 @@ CPU_DOCS = \ doc/c-h8300.texi \ doc/c-hppa.texi \ doc/c-i386.texi \ + doc/c-i860.texi \ doc/c-ip2k.texi \ doc/c-kvx.texi \ doc/c-lm32.texi \ @@ -1145,6 +1148,8 @@ config/tc-ia64.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) config/tc-i386.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) +config/tc-i860.$(OBJEXT): config/$(am__dirstamp) \ + config/$(DEPDIR)/$(am__dirstamp) config/tc-ip2k.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) config/tc-iq2000.$(OBJEXT): config/$(am__dirstamp) \ @@ -1400,6 +1405,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-h8300.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-hppa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-i386.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-i860.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-ia64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-ip2k.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-iq2000.Po@am__quote@ diff --git a/gas/config/tc-i860.c b/gas/config/tc-i860.c new file mode 100644 index 00000000000..a51388700c5 --- /dev/null +++ b/gas/config/tc-i860.c @@ -0,0 +1,1614 @@ +/* tc-i860.c -- Assembler for the Intel i860 architecture. + Copyright (C) 1989-2018 Free Software Foundation, Inc. + + Brought back from the dead and completely reworked + by Jason Eckhardt . + Copyright (C) 2026 René Rebe + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "opcode/i860.h" +#include "elf/i860.h" + + +/* The opcode hash table. */ +static htab_t op_hash = NULL; + +/* These characters always start a comment. */ +const char comment_chars[] = "#!/"; + +/* These characters start a comment at the beginning of a line. */ +const char line_comment_chars[] = "#/"; + +const char line_separator_chars[] = ";"; + +/* Characters that can be used to separate the mantissa from the exponent + in floating point numbers. */ +const char EXP_CHARS[] = "eE"; + +/* Characters that indicate this number is a floating point constant. + As in 0f12.456 or 0d1.2345e12. */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* Register prefix (depends on syntax). */ +static char reg_prefix; + +#define MAX_FIXUPS 2 + +struct i860_it +{ + const char *error; + unsigned long opcode; + enum expand_type expand; + struct i860_fi + { + expressionS exp; + bfd_reloc_code_real_type reloc; + int pcrel; + valueT fup; + } fi[MAX_FIXUPS]; +} the_insn; + +/* The current fixup count. */ +static int fc; + +static char *i860_expr_end; + +/* Indicates error if a pseudo operation was expanded after a branch. */ +static char last_expand; + +/* If true, then warn if any pseudo operations were expanded. */ +static int target_warn_expand = 0; + +/* If true, then XP support is enabled. */ +static int target_xp = 0; + +/* If true, then Intel syntax is enabled (default to AT&T/SVR4 syntax). */ +static int target_intel_syntax = 0; + + +/* Prototypes. */ +static void i860_process_insn (char *); +static void s_dual (int); +static void s_enddual (int); +static void s_atmp (int); +static void s_align_wrapper (int); +static int i860_get_expression (char *); +static bfd_reloc_code_real_type obtain_reloc_for_imm16 (fixS *, long *); +#ifdef DEBUG_I860 +static void print_insn (struct i860_it *); +#endif + +/* Parse the SVR4 selectors of an immediate: @ha, @h, @l, @plt and + @got, @gotoff or @pc, each of these optionally with @ha, @h or @l. */ +static char * +i860_parse_selector (char *s, valueT *fup) +{ + if (strncasecmp (s, "@gottpoffabs", 12) == 0) + { + *fup |= OP_SEL_GOTTPABS; + s += 12; + } + else if (strncasecmp (s, "@gottpoff", 9) == 0) + { + *fup |= OP_SEL_GOTTP; + s += 9; + } + else if (strncasecmp (s, "@tlsgd", 6) == 0) + { + *fup |= OP_SEL_TLSGD; + s += 6; + } + else if (strncasecmp (s, "@tpoff", 6) == 0) + { + *fup |= OP_SEL_TPOFF; + s += 6; + } + else if (strncasecmp (s, "@gotoff", 7) == 0) + { + *fup |= OP_SEL_GOTOFF; + s += 7; + } + else if (strncasecmp (s, "@got", 4) == 0) + { + *fup |= OP_SEL_GOT; + s += 4; + } + else if (strncasecmp (s, "@plt", 4) == 0) + { + *fup |= OP_SEL_PLT; + return s + 4; + } + else if (strncasecmp (s, "@pc", 3) == 0) + { + *fup |= OP_SEL_PC; + s += 3; + } + + if (strncmp (s, "@ha", 3) == 0) + { + *fup |= OP_SEL_HA; + s += 3; + } + else if (strncmp (s, "@h", 2) == 0) + { + *fup |= OP_SEL_H; + s += 2; + } + else if (strncmp (s, "@l", 2) == 0) + { + *fup |= OP_SEL_L; + s += 2; + } + return s; +} + +int +i860_force_relocation (fixS *fix) +{ + if (fix->fx_addnumber & OP_SEL_PLT) + return 1; + return generic_force_reloc (fix); +} + +/* GOT and PLT entries belong to the symbol, not to a section + offset. */ +int +i860_fix_adjustable (fixS *fix) +{ + return (fix->fx_addnumber & (OP_SEL_GOT | OP_SEL_PLT | OP_SEL_TLSGD | OP_SEL_GOTTP + | OP_SEL_GOTTPABS | OP_SEL_TPOFF)) == 0; +} + +const pseudo_typeS md_pseudo_table[] = +{ + {"align", s_align_wrapper, 0}, + {"dual", s_dual, 0}, + {"enddual", s_enddual, 0}, + {"atmp", s_atmp, 0}, + {NULL, 0, 0}, +}; + +/* Dual-instruction mode handling. */ +enum dual +{ + DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, +}; +static enum dual dual_mode = DUAL_OFF; + +/* Handle ".dual" directive. */ +static void +s_dual (int ignore ATTRIBUTE_UNUSED) +{ + if (target_intel_syntax) + dual_mode = DUAL_ON; + else + as_bad (_("Directive .dual available only with -mintel-syntax option")); +} + +/* Handle ".enddual" directive. */ +static void +s_enddual (int ignore ATTRIBUTE_UNUSED) +{ + if (target_intel_syntax) + dual_mode = DUAL_OFF; + else + as_bad (_("Directive .enddual available only with -mintel-syntax option")); +} + +/* Temporary register used when expanding assembler pseudo operations. */ +static int atmp = 31; + +static void +s_atmp (int ignore ATTRIBUTE_UNUSED) +{ + int temp; + + if (! target_intel_syntax) + { + as_bad (_("Directive .atmp available only with -mintel-syntax option")); + demand_empty_rest_of_line (); + return; + } + + if (strncmp (input_line_pointer, "sp", 2) == 0) + { + input_line_pointer += 2; + atmp = 2; + } + else if (strncmp (input_line_pointer, "fp", 2) == 0) + { + input_line_pointer += 2; + atmp = 3; + } + else if (strncmp (input_line_pointer, "r", 1) == 0) + { + input_line_pointer += 1; + temp = get_absolute_expression (); + if (temp >= 0 && temp <= 31) + atmp = temp; + else + as_bad (_("Unknown temporary pseudo register")); + } + else + { + as_bad (_("Unknown temporary pseudo register")); + } + demand_empty_rest_of_line (); +} + +/* Handle ".align" directive depending on syntax mode. + AT&T/SVR4 syntax uses the standard align directive. However, + the Intel syntax additionally allows keywords for the alignment + parameter: ".align type", where type is one of {.short, .long, + .quad, .single, .double} representing alignments of 2, 4, + 16, 4, and 8, respectively. */ +static void +s_align_wrapper (int arg) +{ + char *parm = input_line_pointer; + + if (target_intel_syntax) + { + /* Replace a keyword with the equivalent integer so the + standard align routine can parse the directive. */ + if (strncmp (parm, ".short", 6) == 0) + memcpy (parm, " 2", 6); + else if (strncmp (parm, ".long", 5) == 0) + memcpy (parm, " 4", 5); + else if (strncmp (parm, ".quad", 5) == 0) + memcpy (parm, " 16", 5); + else if (strncmp (parm, ".single", 7) == 0) + memcpy (parm, " 4", 7); + else if (strncmp (parm, ".double", 7) == 0) + memcpy (parm, " 8", 7); + + while (*input_line_pointer == ' ') + ++input_line_pointer; + } + + s_align_bytes (arg); +} + +/* This function is called once, at assembler startup time. It should + set up all the tables and data structures that the MD part of the + assembler will need. */ +void +md_begin (void) +{ + int lose = 0; + unsigned int i = 0; + + op_hash = str_htab_create (); + + while (i860_opcodes[i].name != NULL) + { + const char *name = i860_opcodes[i].name; + if (str_hash_insert (op_hash, name, &i860_opcodes[i], 0) != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s'\n"), + i860_opcodes[i].name); + lose = 1; + } + do + { + if (i860_opcodes[i].match & i860_opcodes[i].lose) + { + fprintf (stderr, + _("internal error: losing opcode: `%s' \"%s\"\n"), + i860_opcodes[i].name, i860_opcodes[i].args); + lose = 1; + } + ++i; + } + while (i860_opcodes[i].name != NULL + && strcmp (i860_opcodes[i].name, name) == 0); + } + + if (lose) + as_fatal (_("Defective assembler. No assembly attempted.")); + + /* Set the register prefix for either Intel or AT&T/SVR4 syntax. */ + reg_prefix = target_intel_syntax ? 0 : '%'; +} + +/* This is the core of the machine-dependent assembler. STR points to a + machine dependent instruction. This function emits the frags/bytes + it assembles to. */ +/* Addresses are not known yet and a frag can end anywhere: count from the last + alignment of at least 8 bytes, or the start of the section. */ +static int +i860_dual_aligned_p (void) +{ + valueT offset = 0; + fragS *f; + + for (f = frchain_now->frch_root; f != NULL && f != frag_now; f = f->fr_next) + switch (f->fr_type) + { + case rs_align: + case rs_align_code: + if (f->fr_offset >= 3) + offset = 0; + else + return 1; + break; + case rs_fill: + offset += f->fr_fix + f->fr_var * f->fr_offset; + break; + default: + return 1; + } + offset += frag_now_fix_octets (); + return (offset & 7) == 0; +} + +void +md_assemble (char *str) +{ + char *destp; + int num_opcodes = 1; + int i; + struct i860_it pseudo[3]; + + gas_assert (str); + fc = 0; + + /* Assemble the instruction. */ + i860_process_insn (str); + + /* Check for expandable flag to produce pseudo-instructions. This + is an undesirable feature that should be avoided. */ + if (the_insn.expand != 0 && the_insn.expand != XP_ONLY + && ! (the_insn.fi[0].fup & (OP_SEL_HA | OP_SEL_H | OP_SEL_L | OP_SEL_GOT + | OP_SEL_GOTOFF | OP_SEL_PLT | OP_SEL_PC + | OP_SEL_TLSGD | OP_SEL_GOTTP + | OP_SEL_GOTTPABS | OP_SEL_TPOFF))) + { + for (i = 0; i < 3; i++) + pseudo[i] = the_insn; + + fc = 1; + switch (the_insn.expand) + { + + case E_DELAY: + num_opcodes = 1; + break; + + case E_MOV: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) + break; + + /* Emit "or l%const,r0,ireg_dest". */ + pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + /* Emit "orh h%const,ireg_dest,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 + | ((the_insn.opcode & 0x001f0000) << 5); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + num_opcodes = 2; + break; + + case E_ADDR: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) + break; + + /* Emit "orh ha%addr_expr,ireg_src2,r31". */ + pseudo[0].opcode = 0xec000000 | (the_insn.opcode & 0x03e00000) + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_HA); + + /* Emit "l%addr_expr(r31),ireg_dest". We pick up the fixup + information from the original instruction. */ + pseudo[1].opcode = (the_insn.opcode & ~0x03e00000) | (atmp << 21); + pseudo[1].fi[0].fup = the_insn.fi[0].fup | OP_SEL_L; + + num_opcodes = 2; + break; + + case E_U32: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 16) + && the_insn.fi[0].exp.X_add_number >= 0)) + break; + + /* Emit "$(opcode)h h%const,ireg_src2,r31". */ + pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + /* Emit "$(opcode) l%const,r31,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 + | (atmp << 21); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + num_opcodes = 2; + break; + + case E_AND: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 16) + && the_insn.fi[0].exp.X_add_number >= 0)) + break; + + /* Emit "andnot h%const,ireg_src2,r31". */ + pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + pseudo[0].fi[0].exp.X_add_number = + -1 - the_insn.fi[0].exp.X_add_number; + + /* Emit "andnot l%const,r31,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 + | (atmp << 21); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + pseudo[1].fi[0].exp.X_add_number = + -1 - the_insn.fi[0].exp.X_add_number; + + num_opcodes = 2; + break; + + case E_S32: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) + break; + + /* Emit "orh h%const,r0,r31". */ + pseudo[0].opcode = 0xec000000 | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + /* Emit "or l%const,r31,r31". */ + pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + /* Emit "r31,ireg_src2,ireg_dest". */ + pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); + pseudo[2].fi[0].fup = OP_IMM_S16; + + num_opcodes = 3; + break; + + default: + as_fatal (_("failed sanity check.")); + } + + the_insn = pseudo[0]; + + /* Warn if an opcode is expanded after a delayed branch. */ + if (num_opcodes > 1 && last_expand == 1) + as_warn (_("Expanded opcode after delayed branch: `%s'"), str); + + /* Warn if an opcode is expanded in dual mode. */ + if (num_opcodes > 1 && dual_mode != DUAL_OFF) + as_warn (_("Expanded opcode in dual mode: `%s'"), str); + + /* Notify if any expansions happen. */ + if (target_warn_expand && num_opcodes > 1) + as_warn (_("An instruction was expanded (%s)"), str); + } + + dwarf2_emit_insn (0); + i = 0; + do + { + int tmp; + + /* Output the opcode. Note that the i860 always reads instructions + as little-endian data. */ + destp = frag_more (4); + number_to_chars_littleendian (destp, the_insn.opcode, 4); + + /* Check for expanded opcode after branch or in dual mode. */ + last_expand = the_insn.fi[0].pcrel; + + /* Output the symbol-dependent stuff. Only btne and bte will ever + loop more than once here, since only they (possibly) have more + than one fixup. */ + for (tmp = 0; tmp < fc; tmp++) + { + if (the_insn.fi[tmp].fup != OP_NONE) + { + fixS *fix; + fix = fix_new_exp (frag_now, + destp - frag_now->fr_literal, + 4, + &the_insn.fi[tmp].exp, + the_insn.fi[tmp].pcrel, + the_insn.fi[tmp].reloc); + + /* Despite the odd name, this is a scratch field. We use + it to encode operand type information. */ + fix->fx_addnumber = the_insn.fi[tmp].fup; + } + } + the_insn = pseudo[++i]; + } + while (--num_opcodes > 0); + +} + +/* Assemble the instruction pointed to by STR. */ +static void +i860_process_insn (char *str) +{ + char *s; + const char *args; + char c; + struct i860_opcode *insn; + char *args_start; + unsigned long opcode; + unsigned int mask; + int match = 0; + int comma = 0; + +#if 1 /* For compiler warnings. */ + args = 0; + insn = 0; + args_start = 0; + opcode = 0; +#endif + + for (s = str; ISLOWER (*s) || *s == '.' || *s == '3' + || *s == '2' || *s == '1'; ++s) + ; + + switch (*s) + { + case '\0': + break; + + case ',': + comma = 1; + + /*FALLTHROUGH*/ + + case ' ': + *s++ = '\0'; + break; + + default: + as_fatal (_("Unknown opcode: `%s'"), str); + } + + /* Check for dual mode ("d.") opcode prefix. */ + if (strncmp (str, "d.", 2) == 0) + { + if (dual_mode == DUAL_ON) + dual_mode = DUAL_ONDDOT; + else + dual_mode = DUAL_DDOT; + str += 2; + } + + if ((insn = (struct i860_opcode *) str_hash_find (op_hash, str)) == NULL) + { + if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) + str -= 2; + as_bad (_("Unknown opcode: `%s'"), str); + return; + } + + if (comma) + *--s = ','; + + args_start = s; + for (;;) + { + int t; + opcode = insn->match; + memset (&the_insn, '\0', sizeof (the_insn)); + fc = 0; + for (t = 0; t < MAX_FIXUPS; t++) + { + the_insn.fi[t].reloc = BFD_RELOC_NONE; + the_insn.fi[t].pcrel = 0; + the_insn.fi[t].fup = OP_NONE; + } + + /* Build the opcode, checking as we go that the operands match. */ + for (args = insn->args; ; ++args) + { + if (fc > MAX_FIXUPS) + abort (); + + switch (*args) + { + + /* End of args. */ + case '\0': + if (*s == '\0') + match = 1; + break; + + /* These must match exactly. */ + case '+': + case '(': + case ')': + case ',': + case ' ': + if (*s++ == *args) + continue; + break; + + /* Must be at least one digit. */ + case '#': + if (ISDIGIT (*s++)) + { + while (ISDIGIT (*s)) + ++s; + continue; + } + break; + + /* Next operand must be a register. */ + case '1': + case '2': + case 'd': + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + + switch (*s) + { + /* Frame pointer. */ + case 'f': + s++; + if (*s++ == 'p') + { + mask = 0x3; + break; + } + goto error; + + /* Stack pointer. */ + case 's': + s++; + if (*s++ == 'p') + { + mask = 0x2; + break; + } + goto error; + + /* Any register r0..r31. */ + case 'r': + s++; + if (!ISDIGIT (c = *s++)) + { + goto error; + } + if (ISDIGIT (*s)) + { + if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) + goto error; + } + else + c -= '0'; + mask = c; + break; + + /* Not this opcode. */ + default: + goto error; + } + + /* Obtained the register, now place it in the opcode. */ + switch (*args) + { + case '1': + opcode |= mask << 11; + continue; + + case '2': + opcode |= mask << 21; + continue; + + case 'd': + opcode |= mask << 16; + continue; + + } + break; + + /* Next operand is a floating point register. */ + case 'e': + case 'f': + case 'g': + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + + if (*s++ == 'f' && ISDIGIT (*s)) + { + mask = *s++; + if (ISDIGIT (*s)) + { + mask = 10 * (mask - '0') + (*s++ - '0'); + if (mask >= 32) + { + break; + } + } + else + mask -= '0'; + + switch (*args) + { + + case 'e': + opcode |= mask << 11; + continue; + + case 'f': + opcode |= mask << 21; + continue; + + case 'g': + opcode |= mask << 16; + if ((opcode & (1 << 10)) && mask != 0 + && (mask == ((opcode >> 11) & 0x1f))) + as_warn (_("Pipelined instruction: fsrc1 = fdest")); + continue; + } + } + break; + + /* Next operand must be a control register. */ + case 'c': + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + + if (strncmp (s, "fir", 3) == 0) + { + opcode |= 0x0 << 21; + s += 3; + continue; + } + if (strncmp (s, "psr", 3) == 0) + { + opcode |= 0x1 << 21; + s += 3; + continue; + } + if (strncmp (s, "dirbase", 7) == 0) + { + opcode |= 0x2 << 21; + s += 7; + continue; + } + if (strncmp (s, "db", 2) == 0) + { + opcode |= 0x3 << 21; + s += 2; + continue; + } + if (strncmp (s, "fsr", 3) == 0) + { + opcode |= 0x4 << 21; + s += 3; + continue; + } + if (strncmp (s, "epsr", 4) == 0) + { + opcode |= 0x5 << 21; + s += 4; + continue; + } + /* The remaining control registers are XP only. */ + if (target_xp && strncmp (s, "bear", 4) == 0) + { + opcode |= 0x6 << 21; + s += 4; + continue; + } + if (target_xp && strncmp (s, "ccr", 3) == 0) + { + opcode |= 0x7 << 21; + s += 3; + continue; + } + if (target_xp && strncmp (s, "p0", 2) == 0) + { + opcode |= 0x8 << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p1", 2) == 0) + { + opcode |= 0x9 << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p2", 2) == 0) + { + opcode |= 0xa << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p3", 2) == 0) + { + opcode |= 0xb << 21; + s += 2; + continue; + } + break; + + /* 5-bit immediate in src1. */ + case '5': + if (! i860_get_expression (s)) + { + s = i860_expr_end; + the_insn.fi[fc].fup |= OP_IMM_U5; + fc++; + continue; + } + break; + + /* 26-bit immediate, relative branch (lbroff). */ + case 'l': + the_insn.fi[fc].pcrel = 1; + the_insn.fi[fc].fup |= OP_IMM_BR26; + goto immediate; + + /* 16-bit split immediate, relative branch (sbroff). */ + case 'r': + the_insn.fi[fc].pcrel = 1; + the_insn.fi[fc].fup |= OP_IMM_BR16; + goto immediate; + + /* 16-bit split immediate. */ + case 's': + the_insn.fi[fc].fup |= OP_IMM_SPLIT16; + goto immediate; + + /* 16-bit split immediate, byte aligned (st.b). */ + case 'S': + the_insn.fi[fc].fup |= OP_IMM_SPLIT16; + goto immediate; + + /* 16-bit split immediate, half-word aligned (st.s). */ + case 'T': + the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN2); + goto immediate; + + /* 16-bit split immediate, word aligned (st.l). */ + case 'U': + the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN4); + goto immediate; + + /* 16-bit immediate. */ + case 'i': + the_insn.fi[fc].fup |= OP_IMM_S16; + goto immediate; + + /* 16-bit immediate, byte aligned (ld.b). */ + case 'I': + the_insn.fi[fc].fup |= OP_IMM_S16; + goto immediate; + + /* 16-bit immediate, half-word aligned (ld.s). */ + case 'J': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN2); + goto immediate; + + /* 16-bit immediate, word aligned (ld.l, {p}fld.l, fst.l). */ + case 'K': + if (insn->name[0] == 'l') + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN4); + else + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE2 | OP_ALIGN4); + goto immediate; + + /* 16-bit immediate, double-word aligned ({p}fld.d, fst.d). */ + case 'L': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN8); + goto immediate; + + /* 16-bit immediate, quad-word aligned (fld.q, fst.q). */ + case 'M': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN16); + + /*FALLTHROUGH*/ + + /* Handle the immediate for either the Intel syntax or + SVR4 syntax. The Intel syntax is "ha%immediate" + whereas SVR4 syntax is "[immediate]@ha". */ + immediate: + if (target_intel_syntax == 0) + { + /* AT&T/SVR4 syntax. */ + if (*s == ' ') + s++; + + /* Note that if i860_get_expression() fails, we will still + have created U entries in the symbol table for the + 'symbols' in the input string. Try not to create U + symbols for registers, etc. */ + if (! i860_get_expression (s)) + s = i860_expr_end; + else + goto error; + + s = i860_parse_selector (s, &the_insn.fi[fc].fup); + + the_insn.expand = insn->expand; + fc++; + + continue; + } + else + { + /* Intel syntax. */ + if (*s == ' ') + s++; + if (strncmp (s, "ha%", 3) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_HA; + s += 3; + } + else if (strncmp (s, "h%", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_H; + s += 2; + } + else if (strncmp (s, "l%", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_L; + s += 2; + } + the_insn.expand = insn->expand; + + /* Note that if i860_get_expression() fails, we will still + have created U entries in the symbol table for the + 'symbols' in the input string. Try not to create U + symbols for registers, etc. */ + if (! i860_get_expression (s)) + s = i860_expr_end; + else + goto error; + + fc++; + continue; + } + break; + + default: + as_fatal (_("failed sanity check.")); + } + break; + } + error: + if (match == 0) + { + /* Args don't match. */ + if (insn[1].name != NULL + && ! strcmp (insn->name, insn[1].name)) + { + ++insn; + s = args_start; + continue; + } + else + { + as_bad (_("Illegal operands for %s"), insn->name); + return; + } + } + break; + } + + /* Set the dual bit on this instruction if necessary. */ + if (dual_mode != DUAL_OFF) + { + if ((opcode & 0xfc000000) == 0x48000000 || opcode == 0xb0000000) + { + /* The instruction is a flop or a fnop, so set its dual bit + (but check that it is 8-byte aligned). */ + if (i860_dual_aligned_p ()) + opcode |= (1 << 9); + else + as_bad (_("'d.%s' must be 8-byte aligned"), insn->name); + + if (dual_mode == DUAL_DDOT) + dual_mode = DUAL_OFF; + else if (dual_mode == DUAL_ONDDOT) + dual_mode = DUAL_ON; + } + else if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) + as_bad (_("Prefix 'd.' invalid for instruction `%s'"), insn->name); + } + + the_insn.opcode = opcode; + + /* Only recognize XP instructions when the user has requested it. */ + if (insn->expand == XP_ONLY && ! target_xp) + as_bad (_("Unknown opcode: `%s'"), insn->name); +} + +static int +i860_get_expression (char *str) +{ + char *save_in; + segT seg; + + save_in = input_line_pointer; + input_line_pointer = str; + seg = expression (&the_insn.fi[fc].exp); + if (seg != absolute_section + && seg != undefined_section + && ! SEG_NORMAL (seg)) + { + the_insn.error = _("bad segment"); + i860_expr_end = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + i860_expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + +const char * +md_atof (int type, char *litP, int *sizeP) +{ + return ieee_md_atof (type, litP, sizeP, true); +} + +/* Write out in current endian mode. */ +void +md_number_to_chars (char *buf, valueT val, int n) +{ + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); +} + +/* This should never be called for i860. */ +int +md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, + segT segtype ATTRIBUTE_UNUSED) +{ + as_fatal (_("relaxation not supported\n")); +} + +#ifdef DEBUG_I860 +static void +print_insn (struct i860_it *insn) +{ + if (insn->error) + fprintf (stderr, "ERROR: %s\n", insn->error); + + fprintf (stderr, "opcode = 0x%08lx\t", insn->opcode); + fprintf (stderr, "expand = 0x%x\t", insn->expand); + fprintf (stderr, "reloc = %s\t\n", + bfd_get_reloc_code_name (insn->reloc)); + fprintf (stderr, "exp = {\n"); + fprintf (stderr, "\t\tX_add_symbol = %s\n", + insn->exp.X_add_symbol ? + (S_GET_NAME (insn->exp.X_add_symbol) ? + S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_op_symbol = %s\n", + insn->exp.X_op_symbol ? + (S_GET_NAME (insn->exp.X_op_symbol) ? + S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_add_number = %lx\n", + insn->exp.X_add_number); + fprintf (stderr, "}\n"); +} +#endif /* DEBUG_I860 */ + + +#ifdef OBJ_ELF +const char md_shortopts[] = "VQ:"; +#else +const char md_shortopts[] = ""; +#endif + +#define OPTION_EB (OPTION_MD_BASE + 0) +#define OPTION_EL (OPTION_MD_BASE + 1) +#define OPTION_WARN_EXPAND (OPTION_MD_BASE + 2) +#define OPTION_XP (OPTION_MD_BASE + 3) +#define OPTION_INTEL_SYNTAX (OPTION_MD_BASE + 4) + +const struct option md_longopts[] = { + { "EB", no_argument, NULL, OPTION_EB }, + { "EL", no_argument, NULL, OPTION_EL }, + { "mwarn-expand", no_argument, NULL, OPTION_WARN_EXPAND }, + { "mxp", no_argument, NULL, OPTION_XP }, + { "mintel-syntax",no_argument, NULL, OPTION_INTEL_SYNTAX }, + { NULL, no_argument, NULL, 0 } +}; +const size_t md_longopts_size = sizeof (md_longopts); + +int +md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) +{ + switch (c) + { + case OPTION_EB: + target_big_endian = 1; + break; + + case OPTION_EL: + target_big_endian = 0; + break; + + case OPTION_WARN_EXPAND: + target_warn_expand = 1; + break; + + case OPTION_XP: + target_xp = 1; + break; + + case OPTION_INTEL_SYNTAX: + target_intel_syntax = 1; + break; + +#ifdef OBJ_ELF + /* SVR4 argument compatibility (-V): print version ID. */ + case 'V': + print_version_id (); + break; + + /* SVR4 argument compatibility (-Qy, -Qn): controls whether + a .comment section should be emitted or not (ignored). */ + case 'Q': + break; +#endif + + default: + return 0; + } + + return 1; +} + +void +md_show_usage (FILE *stream) +{ + fprintf (stream, _("\ + -EL generate code for little endian mode (default)\n\ + -EB generate code for big endian mode\n\ + -mwarn-expand warn if pseudo operations are expanded\n\ + -mxp enable i860XP support (disabled by default)\n\ + -mintel-syntax enable Intel syntax (default to AT&T/SVR4)\n")); +#ifdef OBJ_ELF + /* SVR4 compatibility flags. */ + fprintf (stream, _("\ + -V print assembler version number\n\ + -Qy, -Qn ignored\n")); +#endif +} + + +/* We have no need to default values of symbols. */ +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +{ + return 0; +} + +/* The i860 denotes auto-increment with '++'. */ +void +md_operand (expressionS *exp) +{ + char *s; + + for (s = input_line_pointer; *s; s++) + { + if (s[0] == '+' && s[1] == '+') + { + input_line_pointer += 2; + exp->X_op = O_register; + break; + } + } +} + +/* Round up a section size to the appropriate boundary. */ +valueT +md_section_align (segT segment ATTRIBUTE_UNUSED, + valueT size ATTRIBUTE_UNUSED) +{ + /* Byte alignment is fine. */ + return size; +} + +/* On the i860, a PC-relative offset is relative to the address of the + offset plus its size. */ +long +md_pcrel_from (fixS *fixP) +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +/* Determine the relocation needed for non PC-relative 16-bit immediates. + Also adjust the given immediate as necessary. Finally, check that + all constraints (such as alignment) are satisfied. */ +static bfd_reloc_code_real_type +obtain_reloc_for_imm16 (fixS *fix, long *val) +{ + valueT fup = fix->fx_addnumber; + bfd_reloc_code_real_type reloc; + + if (fix->fx_pcrel) + abort (); + + /* TLS selectors make the symbol thread local, also if undefined here. */ + if (fup & (OP_SEL_TLSGD | OP_SEL_GOTTP | OP_SEL_GOTTPABS | OP_SEL_TPOFF)) + { + if (fix->fx_addsy) + S_SET_THREAD_LOCAL (fix->fx_addsy); + if (fup & OP_SEL_TLSGD) + return (fup & OP_SEL_H) ? BFD_RELOC_860_TLS_GD_HI : BFD_RELOC_860_TLS_GD_LO; + if (fup & OP_SEL_GOTTP) + return (fup & OP_SEL_HA) ? BFD_RELOC_860_TLS_IE_HA : BFD_RELOC_860_TLS_IE_LO1; + if (fup & OP_SEL_GOTTPABS) + return ((fup & OP_SEL_HA) ? BFD_RELOC_860_TLS_IE_ABS_HA + : BFD_RELOC_860_TLS_IE_ABS_LO1); + return (fup & OP_SEL_H) ? BFD_RELOC_860_TLS_LE_HI : BFD_RELOC_860_TLS_LE_LO; + } + + /* The PIC selectors only name a relocation, the symbol is always kept. */ + if (fup & OP_SEL_PC) + return (fup & OP_SEL_HA) ? BFD_RELOC_860_HAPC : BFD_RELOC_860_LOPC; + if (fup & OP_SEL_GOT) + { + if (fup & OP_SEL_HA) + return BFD_RELOC_860_HAGOT; + if (fup & OP_SEL_H) + return BFD_RELOC_860_HIGOT; + if (fup & OP_IMM_SPLIT16) + return (fup & OP_ENCODE1) ? BFD_RELOC_860_SPGOT1 : BFD_RELOC_860_SPGOT0; + return (fup & OP_ENCODE1) ? BFD_RELOC_860_LOGOT1 : BFD_RELOC_860_LOGOT0; + } + if (fup & OP_SEL_GOTOFF) + { + if (fup & OP_SEL_HA) + return BFD_RELOC_860_HAGOTOFF; + if (fup & OP_SEL_H) + return BFD_RELOC_860_HIGOTOFF; + if (fup & OP_IMM_SPLIT16) + return ((fup & OP_ENCODE1) ? BFD_RELOC_860_SPGOTOFF1 + : BFD_RELOC_860_SPGOTOFF0); + if (fup & OP_ENCODE3) + return BFD_RELOC_860_LOGOTOFF3; + if (fup & OP_ENCODE2) + return BFD_RELOC_860_LOGOTOFF2; + return ((fup & OP_ENCODE1) ? BFD_RELOC_860_LOGOTOFF1 + : BFD_RELOC_860_LOGOTOFF0); + } + + /* Check alignment restrictions. */ + if ((fup & OP_ALIGN2) && (*val & 0x1)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 2 alignment")); + else if ((fup & OP_ALIGN4) && (*val & 0x3)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 4 alignment")); + else if ((fup & OP_ALIGN8) && (*val & 0x7)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 8 alignment")); + else if ((fup & OP_ALIGN16) && (*val & 0xf)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 16 alignment")); + + if (fup & OP_SEL_HA) + { + *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0); + reloc = BFD_RELOC_860_HIGHADJ; + } + else if (fup & OP_SEL_H) + { + *val >>= 16; + reloc = BFD_RELOC_860_HIGH; + } + else if (fup & OP_SEL_L) + { + int num_encode; + if (fup & OP_IMM_SPLIT16) + { + if (fup & OP_ENCODE1) + { + num_encode = 1; + reloc = BFD_RELOC_860_SPLIT1; + } + else if (fup & OP_ENCODE2) + { + num_encode = 2; + reloc = BFD_RELOC_860_SPLIT2; + } + else + { + num_encode = 0; + reloc = BFD_RELOC_860_SPLIT0; + } + } + else + { + if (fup & OP_ENCODE1) + { + num_encode = 1; + reloc = BFD_RELOC_860_LOW1; + } + else if (fup & OP_ENCODE2) + { + num_encode = 2; + reloc = BFD_RELOC_860_LOW2; + } + else if (fup & OP_ENCODE3) + { + num_encode = 3; + reloc = BFD_RELOC_860_LOW3; + } + else + { + num_encode = 0; + reloc = BFD_RELOC_860_LOW0; + } + } + + /* Preserve size encode bits. */ + *val &= ~((1 << num_encode) - 1); + } + else + { + /* No selector. What reloc do we generate (???)? */ + reloc = BFD_RELOC_32; + } + + return reloc; +} + +/* Attempt to simplify or eliminate a fixup. To indicate that a fixup + has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL, + we will have to generate a reloc entry. */ + +void +md_apply_fix (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED) +{ + char *buf; + long val = *valP; + unsigned long insn; + valueT fup; + + buf = fix->fx_frag->fr_literal + fix->fx_where; + + /* We stored a fix-up in this oddly-named scratch field. */ + fup = fix->fx_addnumber; + + /* Recall that earlier we stored the opcode little-endian. Data fix-ups + have no opcode and can be smaller than a word. */ + insn = fup != OP_NONE ? bfd_getl32 (buf) : 0; + + /* Determine the necessary relocations as well as inserting an + immediate into the instruction. */ + if (fup & OP_IMM_U5) + { + if (val & ~0x1f) + as_bad_where (fix->fx_file, fix->fx_line, + _("5-bit immediate too large")); + if (fix->fx_addsy) + as_bad_where (fix->fx_file, fix->fx_line, + _("5-bit field must be absolute")); + + insn |= (val & 0x1f) << 11; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + else if (fup & OP_IMM_S16) + { + fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); + + /* Insert the immediate. */ + if (fix->fx_addsy) + fix->fx_done = 0; + else + { + insn |= val & 0xffff; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup & OP_IMM_U16) + abort (); + + else if (fup & OP_IMM_SPLIT16) + { + fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); + + /* Insert the immediate. */ + if (fix->fx_addsy) + fix->fx_done = 0; + else + { + insn |= val & 0x7ff; + insn |= (val & 0xf800) << 5; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup & OP_IMM_BR16) + { + if (val & 0x3) + as_bad_where (fix->fx_file, fix->fx_line, + _("A branch offset requires 0 MOD 4 alignment")); + + val = val >> 2; + + /* Insert the immediate. */ + if (fix->fx_addsy) + { + fix->fx_done = 0; + fix->fx_r_type = BFD_RELOC_860_PC16; + } + else + { + insn |= (val & 0x7ff); + insn |= ((val & 0xf800) << 5); + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup & OP_IMM_BR26) + { + if (val & 0x3) + as_bad_where (fix->fx_file, fix->fx_line, + _("A branch offset requires 0 MOD 4 alignment")); + + val >>= 2; + + /* Insert the immediate. */ + if (fix->fx_addsy) + { + fix->fx_r_type = (fup & OP_SEL_PLT) ? BFD_RELOC_860_PLT26 + : BFD_RELOC_860_PC26; + fix->fx_done = 0; + } + else + { + insn |= (val & 0x3ffffff); + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup != OP_NONE) + { + as_bad_where (fix->fx_file, fix->fx_line, + _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup); + abort (); + } + else + { + /* I believe only fix-ups such as ".long .ep.main-main+0xc8000000" + reach here (???). */ + if (fix->fx_addsy) + { + if (fix->fx_size != 4) + as_bad_where (fix->fx_file, fix->fx_line, + _("no %d byte data relocation"), fix->fx_size); + fix->fx_r_type = BFD_RELOC_32; + fix->fx_done = 0; + } + else + { + md_number_to_chars (buf, val, fix->fx_size); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } +} + +/* Generate a machine dependent reloc from a fixup. */ +arelent* +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, + fixS *fixp) +{ + arelent *reloc; + + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = fixp->fx_offset; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + + if (! reloc->howto) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "Cannot represent %s relocation in object file", + bfd_get_reloc_code_name (fixp->fx_r_type)); + } + return reloc; +} + +/* This is called from HANDLE_ALIGN in write.c. Fill in the contents + of an rs_align_code fragment. */ + +void +i860_handle_align (fragS *fragp) +{ + /* Instructions are always stored little-endian on the i860. */ + static const unsigned char le_nop[] = { 0x00, 0x00, 0x00, 0xA0 }; + + 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; + + /* Make sure we are on a 4-byte boundary, in case someone has been + putting data into a text section. */ + if (bytes & 3) + { + int fix = bytes & 3; + memset (p, 0, fix); + p += fix; + fragp->fr_fix += fix; + } + + memcpy (p, le_nop, 4); + fragp->fr_var = 4; +} + +/* This is called after a user-defined label is seen. We check + if the label has a double colon (valid in Intel syntax mode only), + in which case it should be externalized. */ + +void +i860_check_label (symbolS *labelsym) +{ + /* At this point, the current line pointer is sitting on the character + just after the first colon on the label. */ + if (target_intel_syntax && *input_line_pointer == ':') + { + S_SET_EXTERNAL (labelsym); + input_line_pointer++; + } +} diff --git a/gas/config/tc-i860.h b/gas/config/tc-i860.h new file mode 100644 index 00000000000..c6592511618 --- /dev/null +++ b/gas/config/tc-i860.h @@ -0,0 +1,101 @@ +/* tc-i860.h -- Header file for the i860. + Copyright (C) 1991-2018 Free Software Foundation, Inc. + + Brought back from the dead and completely reworked + by Jason Eckhardt . + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef TC_I860 +#define TC_I860 1 + +enum i860_fix_info +{ + OP_NONE = 0x00000, + OP_IMM_U5 = 0x00001, + OP_IMM_S16 = 0x00002, + OP_IMM_U16 = 0x00004, + OP_IMM_SPLIT16 = 0x00008, + OP_IMM_BR26 = 0x00010, + OP_IMM_BR16 = 0x00020, + OP_ENCODE1 = 0x00040, + OP_ENCODE2 = 0x00080, + OP_ENCODE3 = 0x00100, + OP_SEL_HA = 0x00200, + OP_SEL_H = 0x00400, + OP_SEL_L = 0x00800, + OP_SEL_GOT = 0x01000, + OP_SEL_GOTOFF = 0x02000, + OP_SEL_PLT = 0x04000, + OP_ALIGN2 = 0x08000, + OP_ALIGN4 = 0x10000, + OP_ALIGN8 = 0x20000, + OP_ALIGN16 = 0x40000, + OP_SEL_PC = 0x80000, + OP_SEL_TLSGD = 0x100000, + OP_SEL_GOTTP = 0x200000, + OP_SEL_GOTTPABS = 0x400000, + OP_SEL_TPOFF = 0x800000 +}; + +/* Set the endianness we are using. Default to little endian. */ +#ifndef TARGET_BYTES_BIG_ENDIAN +#define TARGET_BYTES_BIG_ENDIAN 0 +#endif + +/* Whether or not the target is big endian. */ +extern int target_big_endian; + +/* BFD target architecture. */ +#define TARGET_ARCH bfd_arch_i860 + +/* The target BFD format. */ +#ifdef OBJ_ELF +#define TARGET_FORMAT (target_big_endian ? "elf32-i860" : "elf32-i860-little") +#else +#error i860 GAS currently supports only the ELF object format +#endif + +#define WORKING_DOT_WORD +#define DIFF_EXPR_OK + +/* Permit temporary numeric labels. */ +#define LOCAL_LABELS_FB 1 +#define LISTING_HEADER "GAS for i860" + +#define md_convert_frag(b,s,f) abort () + +/* Values passed to md_apply_fix don't include the symbol value. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 + +extern int i860_force_relocation (struct fix *); +#define TC_FORCE_RELOCATION(FIX) i860_force_relocation (FIX) +extern int i860_fix_adjustable (struct fix *); +#define tc_fix_adjustable(FIX) i860_fix_adjustable (FIX) + +/* Bits for post-processing of a user defined label to check if + it has a double colon (Intel syntax only). */ +extern void i860_check_label (symbolS *labelsym); +#define tc_check_label(ls) i860_check_label (ls) + +/* Bits for filling in rs_align_code fragments with NOPs. */ +extern void i860_handle_align (struct frag *); +#define HANDLE_ALIGN(sec, fragp) i860_handle_align (fragp) + +#define MAX_MEM_FOR_RS_ALIGN_CODE(p2align, max) (3 + 4 + 4) + +#endif /* TC_I860 */ diff --git a/gas/configure.tgt b/gas/configure.tgt index 7a5645fd9ae..22069ef416b 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -1,6 +1,7 @@ # gas target specific configuration file. This is a -*- sh -*- file. # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -271,6 +272,7 @@ case ${generic_target} in ia16-*-elf*) fmt=elf ;; + i860-*-*) fmt=elf endian=little ;; ia64-*-elf*) fmt=elf ;; ia64-*-*vms*) fmt=elf em=vms ;; ia64-*-linux-*) fmt=elf em=linux ;; diff --git a/gas/doc/all.texi b/gas/doc/all.texi index 83418951b13..ccf5603e4d8 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -41,6 +41,7 @@ @set HPPA @set I370 @set I80386 +@set I860 @set IA64 @set IP2K @set KVX diff --git a/gas/doc/as.texi b/gas/doc/as.texi index 5d7772d62d3..78108597831 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -4802,7 +4802,7 @@ required alignment; this can be useful if you want the alignment to be filled with no-op instructions when appropriate. The way the required alignment is specified varies from system to system. -For the arc, hppa, i386 using ELF, iq2000, m68k, or1k, +For the arc, hppa, i386 using ELF, i860, iq2000, m68k, or1k, s390, sparc, tic4x and xtensa, the first expression is the alignment request in bytes. For example @samp{.align 8} advances the location counter until it is a multiple of 8. If the location counter @@ -8318,6 +8318,9 @@ subject, see the hardware manufacturer's manual. @ifset I80386 * i386-Dependent:: Intel 80386 and AMD x86-64 Dependent Features @end ifset +@ifset I860 +* i860-Dependent:: Intel 80860 Dependent Features +@end ifset @ifset IA64 * IA-64-Dependent:: Intel IA-64 Dependent Features @end ifset @@ -8539,6 +8542,10 @@ family. @include c-i386.texi @end ifset +@ifset I860 +@include c-i860.texi +@end ifset + @ifset IA64 @include c-ia64.texi @end ifset diff --git a/gas/doc/c-i860.texi b/gas/doc/c-i860.texi new file mode 100644 index 00000000000..6e6726b965b --- /dev/null +++ b/gas/doc/c-i860.texi @@ -0,0 +1,197 @@ +@c Copyright (C) 2000-2018 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node i860-Dependent +@chapter Intel i860 Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter Intel i860 Dependent Features +@end ifclear + +@ignore +@c FIXME: This is basically a stub for i860. There is tons more information +that I will add later (jle@cygnus.com). +@end ignore + +@cindex i860 support +@menu +* Notes-i860:: i860 Notes +* Options-i860:: i860 Command-line Options +* Directives-i860:: i860 Machine Directives +* Opcodes for i860:: i860 Opcodes +* Syntax of i860:: i860 Syntax +@end menu + +@node Notes-i860 +@section i860 Notes +This is a fairly complete i860 assembler which is compatible with the +UNIX System V/860 Release 4 assembler. However, it does not currently +support SVR4 PIC (i.e., @code{@@GOT, @@GOTOFF, @@PLT}). + +Like the SVR4/860 assembler, the output object format is ELF32. Currently, +this is the only supported object format. If there is sufficient interest, +other formats such as COFF may be implemented. + +Both the Intel and AT&T/SVR4 syntaxes are supported, with the latter +being the default. One difference is that AT&T syntax requires the '%' +prefix on register names while Intel syntax does not. Another difference +is in the specification of relocatable expressions. The Intel syntax +is @code{ha%expression} whereas the SVR4 syntax is @code{[expression]@@ha} +(and similarly for the "l" and "h" selectors). +@node Options-i860 +@section i860 Command-line Options +@subsection SVR4 compatibility options +@table @code +@item -V +Print assembler version. +@item -Qy +Ignored. +@item -Qn +Ignored. +@end table +@subsection Other options +@table @code +@item -EL +Select little endian output (this is the default). +@item -EB +Select big endian output. Note that the i860 always reads instructions +as little endian data, so this option only effects data and not +instructions. +@item -mwarn-expand +Emit a warning message if any pseudo-instruction expansions occurred. +For example, a @code{or} instruction with an immediate larger than 16-bits +will be expanded into two instructions. This is a very undesirable feature to +rely on, so this flag can help detect any code where it happens. One +use of it, for instance, has been to find and eliminate any place +where @code{gcc} may emit these pseudo-instructions. +@item -mxp +Enable support for the i860XP instructions and control registers. By default, +this option is disabled so that only the base instruction set (i.e., i860XR) +is supported. +@item -mintel-syntax +The i860 assembler defaults to AT&T/SVR4 syntax. This option enables the +Intel syntax. +@end table + +@node Directives-i860 +@section i860 Machine Directives + +@cindex machine directives, i860 +@cindex i860 machine directives + +@table @code +@cindex @code{dual} directive, i860 +@item .dual +Enter dual instruction mode. While this directive is supported, the +preferred way to use dual instruction mode is to explicitly code +the dual bit with the @code{d.} prefix. +@end table + +@table @code +@cindex @code{enddual} directive, i860 +@item .enddual +Exit dual instruction mode. While this directive is supported, the +preferred way to use dual instruction mode is to explicitly code +the dual bit with the @code{d.} prefix. +@end table + +@table @code +@cindex @code{atmp} directive, i860 +@item .atmp +Change the temporary register used when expanding pseudo operations. The +default register is @code{r31}. +@end table + +The @code{.dual}, @code{.enddual}, and @code{.atmp} directives are available only in the Intel syntax mode. + +Both syntaxes allow for the standard @code{.align} directive. However, +the Intel syntax additionally allows keywords for the alignment +parameter: "@code{.align type}", where `type' is one of @code{.short}, @code{.long}, +@code{.quad}, @code{.single}, @code{.double} representing alignments of 2, 4, +16, 4, and 8, respectively. + +@node Opcodes for i860 +@section i860 Opcodes + +@cindex opcodes, i860 +@cindex i860 opcodes +All of the Intel i860XR and i860XP machine instructions are supported. Please see +either @emph{i860 Microprocessor Programmer's Reference Manual} or @emph{i860 Microprocessor Architecture} for more information. +@subsection Other instruction support (pseudo-instructions) +For compatibility with some other i860 assemblers, a number of +pseudo-instructions are supported. While these are supported, they are +a very undesirable feature that should be avoided -- in particular, when +they result in an expansion to multiple actual i860 instructions. Below +are the pseudo-instructions that result in expansions. +@itemize @bullet +@item Load large immediate into general register: + +The pseudo-instruction @code{mov imm,%rn} (where the immediate does +not fit within a signed 16-bit field) will be expanded into: +@smallexample +orh large_imm@@h,%r0,%rn +or large_imm@@l,%rn,%rn +@end smallexample +@item Load/store with relocatable address expression: + +For example, the pseudo-instruction @code{ld.b addr_exp(%rx),%rn} +will be expanded into: +@smallexample +orh addr_exp@@ha,%rx,%r31 +ld.l addr_exp@@l(%r31),%rn +@end smallexample + +The analogous expansions apply to @code{ld.x, st.x, fld.x, pfld.x, fst.x}, and @code{pst.x} as well. +@item Signed large immediate with add/subtract: + +If any of the arithmetic operations @code{adds, addu, subs, subu} are used +with an immediate larger than 16-bits (signed), then they will be expanded. +For instance, the pseudo-instruction @code{adds large_imm,%rx,%rn} expands to: +@smallexample +orh large_imm@@h,%r0,%r31 +or large_imm@@l,%r31,%r31 +adds %r31,%rx,%rn +@end smallexample +@item Unsigned large immediate with logical operations: + +Logical operations (@code{or, andnot, or, xor}) also result in expansions. +The pseudo-instruction @code{or large_imm,%rx,%rn} results in: +@smallexample +orh large_imm@@h,%rx,%r31 +or large_imm@@l,%r31,%rn +@end smallexample + +Similarly for the others, except for @code{and} which expands to: +@smallexample +andnot (-1 - large_imm)@@h,%rx,%r31 +andnot (-1 - large_imm)@@l,%r31,%rn +@end smallexample +@end itemize + +@node Syntax of i860 +@section i860 Syntax +@menu +* i860-Chars:: Special Characters +@end menu + +@node i860-Chars +@subsection Special Characters + +@cindex line comment character, i860 +@cindex i860 line comment character +The presence of a @samp{#} appearing anywhere on a line indicates the +start of a comment that extends to the end of that line. + +If a @samp{#} appears as the first character of a line then the whole +line is treated as a comment, but in this case the line can also be a +logical line number directive (@pxref{Comments}) or a preprocessor +control command (@pxref{Preprocessing}). + +@cindex line separator, i860 +@cindex statement separator, i860 +@cindex i860 line separator +The @samp{;} character can be used to separate statements on the same +line. diff --git a/gas/doc/local.mk b/gas/doc/local.mk index 4185cfe9a3c..fb9c6eb320e 100644 --- a/gas/doc/local.mk +++ b/gas/doc/local.mk @@ -60,6 +60,7 @@ CPU_DOCS = \ %D%/c-h8300.texi \ %D%/c-hppa.texi \ %D%/c-i386.texi \ + %D%/c-i860.texi \ %D%/c-ip2k.texi \ %D%/c-kvx.texi \ %D%/c-lm32.texi \ diff --git a/gas/po/POTFILES.in b/gas/po/POTFILES.in index c0ce266129e..6bfce7d362c 100644 --- a/gas/po/POTFILES.in +++ b/gas/po/POTFILES.in @@ -82,6 +82,8 @@ config/tc-hppa.c config/tc-hppa.h config/tc-i386.c config/tc-i386.h +config/tc-i860.c +config/tc-i860.h config/tc-ia64.c config/tc-ia64.h config/tc-ip2k.c diff --git a/include/elf/i860.h b/include/elf/i860.h index 45a7225b4be..cc033a6ebf9 100644 --- a/include/elf/i860.h +++ b/include/elf/i860.h @@ -33,6 +33,17 @@ START_RELOC_NUMBERS (elf_i860_reloc_type) RELOC_NUMBER (R_860_GLOB_DAT, 0x03) /* S, Create GOT entry */ RELOC_NUMBER (R_860_JUMP_SLOT, 0x04) /* S+A, Create PLT entry */ RELOC_NUMBER (R_860_RELATIVE, 0x05) /* B+A, Adj by program base */ + RELOC_NUMBER (R_860_TLS_DTPMOD32, 0x06) /* module of the symbol */ + RELOC_NUMBER (R_860_TLS_DTPOFF32, 0x07) /* offset in its TLS block */ + RELOC_NUMBER (R_860_TLS_TPOFF32, 0x08) /* offset from the thread pointer */ + RELOC_NUMBER (R_860_TLS_GD_HI, 0x10) /* GOT offset of a DTPMOD, DTPOFF pair >> 16 */ + RELOC_NUMBER (R_860_TLS_GD_LO, 0x11) + RELOC_NUMBER (R_860_TLS_IE_HA, 0x12) /* hiadj(GOT offset of a TPOFF) */ + RELOC_NUMBER (R_860_TLS_IE_LO1, 0x13) + RELOC_NUMBER (R_860_TLS_IE_ABS_HA, 0x14) /* hiadj(address of a TPOFF) */ + RELOC_NUMBER (R_860_TLS_IE_ABS_LO1, 0x15) + RELOC_NUMBER (R_860_TLS_LE_HI, 0x16) /* offset from the thread pointer >> 16 */ + RELOC_NUMBER (R_860_TLS_LE_LO, 0x17) RELOC_NUMBER (R_860_PC26, 0x30) /* (S+A-P) >> 2 */ RELOC_NUMBER (R_860_PLT26, 0x31) /* (L+A-P) >> 2 */ RELOC_NUMBER (R_860_PC16, 0x32) /* (S+A-P) >> 2 */ diff --git a/include/opcode/i860.h b/include/opcode/i860.h new file mode 100644 index 00000000000..717a9dd3111 --- /dev/null +++ b/include/opcode/i860.h @@ -0,0 +1,507 @@ +/* Table of opcodes for the i860. + Copyright (C) 1989-2018 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe + + This file is part of the GNU opcodes library. + + GAS/GDB is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS/GDB 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 or GDB; see the file COPYING3. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* Structure of an opcode table entry. */ +struct i860_opcode +{ + /* The opcode name. */ + const char *name; + + /* Bits that must be set. */ + unsigned long match; + + /* Bits that must not be set. */ + unsigned long lose; + + const char *args; + + /* Nonzero if this is a possible expand-instruction. */ + char expand; +}; + + +enum expand_type +{ + E_MOV = 1, E_ADDR, E_U32, E_AND, E_S32, E_DELAY, XP_ONLY +}; + + +/* All i860 opcodes are 32 bits, except for the pseudo-instructions + and the operations utilizing a 32-bit address expression, an + unsigned 32-bit constant, or a signed 32-bit constant. + These opcodes are expanded into a two-instruction sequence for + any situation where the immediate operand does not fit in 32 bits. + In the case of the add and subtract operations the expansion is + to a three-instruction sequence (ex: orh, or, adds). In cases + where the address is to be relocated, the instruction is + expanded to handle the worse case, this could be optimized at + the final link if the actual address were known. + + The pseudoinstructions are: mov, fmov, pmov, nop, and fnop. + These instructions are implemented as a one or two instruction + sequence of other operations. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character + for each operand of the instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 src1 integer register. + 2 src2 integer register. + d dest register. + c ctrlreg control register. + i 16 bit immediate. + I 16 bit immediate, aligned 2^0. (ld.b) + J 16 bit immediate, aligned 2^1. (ld.s) + K 16 bit immediate, aligned 2^2. (ld.l, {p}fld.l, fst.l) + L 16 bit immediate, aligned 2^3. ({p}fld.d, fst.d) + M 16 bit immediate, aligned 2^4. ({p}fld.q, fst.q) + 5 5 bit immediate. + l lbroff 26 bit PC relative immediate. + r sbroff 16 bit PC relative immediate. + s split 16 bit immediate. + S split 16 bit immediate, aligned 2^0. (st.b) + T split 16 bit immediate, aligned 2^1. (st.s) + U split 16 bit immediate, aligned 2^2. (st.l) + e src1 floating point register. + f src2 floating point register. + g dest floating point register. */ + + +/* The order of the opcodes in this table is significant. The assembler + requires that all instances of the same mnemonic must be consecutive. + If they aren't, the assembler will not function properly. + + The order of opcodes does not affect the disassembler. */ + +static const struct i860_opcode i860_opcodes[] = +{ +/* REG-Format Instructions. */ +{ "ld.c", 0x30000000, 0xcc000000, "c,d", 0 }, /* ld.c csrc2,idest */ +{ "ld.b", 0x00000000, 0xfc000000, "1(2),d", 0 }, /* ld.b isrc1(isrc2),idest */ +{ "ld.b", 0x04000000, 0xf8000000, "I(2),d", E_ADDR }, /* ld.b #const(isrc2),idest */ +{ "ld.s", 0x10000000, 0xec000001, "1(2),d", 0 }, /* ld.s isrc1(isrc2),idest */ +{ "ld.s", 0x14000000, 0xe8000001, "J(2),d", E_ADDR }, /* ld.s #const(isrc2),idest */ +{ "ld.l", 0x10000001, 0xec000000, "1(2),d", 0 }, /* ld.l isrc1(isrc2),idest */ +{ "ld.l", 0x14000001, 0xe8000000, "K(2),d", E_ADDR }, /* ld.l #const(isrc2),idest */ + +{ "st.c", 0x38000000, 0xc4000000, "1,c", 0 }, /* st.c isrc1ni,csrc2 */ +{ "st.b", 0x0c000000, 0xf0000000, "1,S(2)", E_ADDR }, /* st.b isrc1ni,#const(isrc2) */ +{ "st.s", 0x1c000000, 0xe0000001, "1,T(2)", E_ADDR }, /* st.s isrc1ni,#const(isrc2) */ +{ "st.l", 0x1c000001, 0xe0000000, "1,U(2)", E_ADDR }, /* st.l isrc1ni,#const(isrc2) */ + +{ "ixfr", 0x08000000, 0xf4000000, "1,g", 0 }, /* ixfr isrc1ni,fdest */ + +{ "fld.l", 0x20000002, 0xdc000001, "1(2),g", 0 }, /* fld.l isrc1(isrc2),fdest */ +{ "fld.l", 0x24000002, 0xd8000001, "K(2),g", E_ADDR }, /* fld.l #const(isrc2),fdest */ +{ "fld.l", 0x20000003, 0xdc000000, "1(2)++,g", 0 }, /* fld.l isrc1(isrc2)++,fdest */ +{ "fld.l", 0x24000003, 0xd8000000, "K(2)++,g", E_ADDR }, /* fld.l #const(isrc2)++,fdest */ +{ "fld.d", 0x20000000, 0xdc000007, "1(2),g", 0 }, /* fld.d isrc1(isrc2),fdest */ +{ "fld.d", 0x24000000, 0xd8000007, "L(2),g", E_ADDR }, /* fld.d #const(isrc2),fdest */ +{ "fld.d", 0x20000001, 0xdc000006, "1(2)++,g", 0 }, /* fld.d isrc1(isrc2)++,fdest */ +{ "fld.d", 0x24000001, 0xd8000006, "L(2)++,g", E_ADDR }, /* fld.d #const(isrc2)++,fdest */ +{ "fld.q", 0x20000004, 0xdc000003, "1(2),g", 0 }, /* fld.q isrc1(isrc2),fdest */ +{ "fld.q", 0x24000004, 0xd8000003, "M(2),g", E_ADDR }, /* fld.q #const(isrc2),fdest */ +{ "fld.q", 0x20000005, 0xdc000002, "1(2)++,g", 0 }, /* fld.q isrc1(isrc2)++,fdest */ +{ "fld.q", 0x24000005, 0xd8000002, "M(2)++,g", E_ADDR }, /* fld.q #const(isrc2)++,fdest */ + +{ "pfld.l", 0x60000002, 0x9c000001, "1(2),g", 0 }, /* pfld.l isrc1(isrc2),fdest */ +{ "pfld.l", 0x64000002, 0x98000001, "K(2),g", E_ADDR }, /* pfld.l #const(isrc2),fdest */ +{ "pfld.l", 0x60000003, 0x9c000000, "1(2)++,g", 0 }, /* pfld.l isrc1(isrc2)++,fdest */ +{ "pfld.l", 0x64000003, 0x98000000, "K(2)++,g", E_ADDR }, /* pfld.l #const(isrc2)++,fdest */ +{ "pfld.d", 0x60000000, 0x9c000007, "1(2),g", 0 }, /* pfld.d isrc1(isrc2),fdest */ +{ "pfld.d", 0x64000000, 0x98000007, "L(2),g", E_ADDR }, /* pfld.d #const(isrc2),fdest */ +{ "pfld.d", 0x60000001, 0x9c000006, "1(2)++,g", 0 }, /* pfld.d isrc1(isrc2)++,fdest */ +{ "pfld.d", 0x64000001, 0x98000006, "L(2)++,g", E_ADDR }, /* pfld.d #const(isrc2)++,fdest */ +{ "pfld.q", 0x60000004, 0x9c000003, "1(2),g", XP_ONLY }, /* pfld.q isrc1(isrc2),fdest */ +{ "pfld.q", 0x64000004, 0x98000003, "L(2),g", XP_ONLY }, /* pfld.q #const(isrc2),fdest */ +{ "pfld.q", 0x60000005, 0x9c000002, "1(2)++,g", XP_ONLY }, /* pfld.q isrc1(isrc2)++,fdest */ +{ "pfld.q", 0x64000005, 0x98000002, "L(2)++,g", XP_ONLY }, /* pfld.q #const(isrc2)++,fdest */ + +{ "fst.l", 0x28000002, 0xd4000001, "g,1(2)", 0 }, /* fst.l fdest,isrc1(isrc2) */ +{ "fst.l", 0x2c000002, 0xd0000001, "g,K(2)", E_ADDR }, /* fst.l fdest,#const(isrc2) */ +{ "fst.l", 0x28000003, 0xd4000000, "g,1(2)++", 0 }, /* fst.l fdest,isrc1(isrc2)++ */ +{ "fst.l", 0x2c000003, 0xd0000000, "g,K(2)++", E_ADDR }, /* fst.l fdest,#const(isrc2)++ */ +{ "fst.d", 0x28000000, 0xd4000007, "g,1(2)", 0 }, /* fst.d fdest,isrc1(isrc2) */ +{ "fst.d", 0x2c000000, 0xd0000007, "g,L(2)", E_ADDR }, /* fst.d fdest,#const(isrc2) */ +{ "fst.d", 0x28000001, 0xd4000006, "g,1(2)++", 0 }, /* fst.d fdest,isrc1(isrc2)++ */ +{ "fst.d", 0x2c000001, 0xd0000006, "g,L(2)++", E_ADDR }, /* fst.d fdest,#const(isrc2)++ */ +{ "fst.q", 0x28000004, 0xd4000003, "g,1(2)", 0 }, /* fst.d fdest,isrc1(isrc2) */ +{ "fst.q", 0x2c000004, 0xd0000003, "g,M(2)", E_ADDR }, /* fst.d fdest,#const(isrc2) */ +{ "fst.q", 0x28000005, 0xd4000002, "g,1(2)++", 0 }, /* fst.d fdest,isrc1(isrc2)++ */ +{ "fst.q", 0x2c000005, 0xd0000002, "g,M(2)++", E_ADDR }, /* fst.d fdest,#const(isrc2)++ */ + +{ "pst.d", 0x3c000000, 0xc0000007, "g,L(2)", E_ADDR }, /* pst.d fdest,#const(isrc2) */ +{ "pst.d", 0x3c000001, 0xc0000006, "g,L(2)++", E_ADDR }, /* pst.d fdest,#const(isrc2)++ */ + +{ "addu", 0x80000000, 0x7c000000, "1,2,d", 0 }, /* addu isrc1,isrc2,idest */ +{ "addu", 0x84000000, 0x78000000, "i,2,d", E_S32 }, /* addu #const,isrc2,idest */ +{ "adds", 0x90000000, 0x6c000000, "1,2,d", 0 }, /* adds isrc1,isrc2,idest */ +{ "adds", 0x94000000, 0x68000000, "i,2,d", E_S32 }, /* adds #const,isrc2,idest */ +{ "subu", 0x88000000, 0x74000000, "1,2,d", 0 }, /* subu isrc1,isrc2,idest */ +{ "subu", 0x8c000000, 0x70000000, "i,2,d", E_S32 }, /* subu #const,isrc2,idest */ +{ "subs", 0x98000000, 0x64000000, "1,2,d", 0 }, /* subs isrc1,isrc2,idest */ +{ "subs", 0x9c000000, 0x60000000, "i,2,d", E_S32 }, /* subs #const,isrc2,idest */ + +{ "shl", 0xa0000000, 0x5c000000, "1,2,d", 0 }, /* shl isrc1,isrc2,idest */ +{ "shl", 0xa4000000, 0x58000000, "i,2,d", 0 }, /* shl #const,isrc2,idest */ +{ "shr", 0xa8000000, 0x54000000, "1,2,d", 0 }, /* shr isrc1,isrc2,idest */ +{ "shr", 0xac000000, 0x50000000, "i,2,d", 0 }, /* shr #const,isrc2,idest */ +{ "shrd", 0xb0000000, 0x4c000000, "1,2,d", 0 }, /* shrd isrc1,isrc2,idest */ +{ "shra", 0xb8000000, 0x44000000, "1,2,d", 0 }, /* shra isrc1,isrc2,idest */ +{ "shra", 0xbc000000, 0x40000000, "i,2,d", 0 }, /* shra #const,isrc2,idest */ + +{ "mov", 0xa0000000, 0x5c00f800, "2,d", 0 }, /* shl r0,isrc2,idest */ +{ "mov", 0x94000000, 0x69e00000, "i,d", E_MOV }, /* adds #const,r0,idest */ +{ "nop", 0xa0000000, 0x5ffff800, "", 0 }, /* shl r0,r0,r0 */ +{ "fnop", 0xb0000000, 0x4ffff800, "", 0 }, /* shrd r0,r0,r0 */ + +{ "trap", 0x44000000, 0xb8000000, "1,2,d", 0 }, /* trap isrc1ni,isrc2,idest */ + +{ "flush", 0x34000004, 0xc81f0003, "L(2)", E_ADDR }, /* flush #const(isrc2) */ +{ "flush", 0x34000005, 0xc81f0002, "L(2)++", E_ADDR }, /* flush #const(isrc2)++ */ + +{ "and", 0xc0000000, 0x3c000000, "1,2,d", 0 }, /* and isrc1,isrc2,idest */ +{ "and", 0xc4000000, 0x38000000, "i,2,d", E_AND }, /* and #const,isrc2,idest */ +{ "andh", 0xcc000000, 0x30000000, "i,2,d", 0 }, /* andh #const,isrc2,idest */ +{ "andnot", 0xd0000000, 0x2c000000, "1,2,d", 0 }, /* andnot isrc1,isrc2,idest */ +{ "andnot", 0xd4000000, 0x28000000, "i,2,d", E_U32 }, /* andnot #const,isrc2,idest */ +{ "andnoth", 0xdc000000, 0x20000000, "i,2,d", 0 }, /* andnoth #const,isrc2,idest */ +{ "or", 0xe0000000, 0x1c000000, "1,2,d", 0 }, /* or isrc1,isrc2,idest */ +{ "or", 0xe4000000, 0x18000000, "i,2,d", E_U32 }, /* or #const,isrc2,idest */ +{ "orh", 0xec000000, 0x10000000, "i,2,d", 0 }, /* orh #const,isrc2,idest */ +{ "xor", 0xf0000000, 0x0c000000, "1,2,d", 0 }, /* xor isrc1,isrc2,idest */ +{ "xor", 0xf4000000, 0x08000000, "i,2,d", E_U32 }, /* xor #const,isrc2,idest */ +{ "xorh", 0xfc000000, 0x00000000, "i,2,d", 0 }, /* xorh #const,isrc2,idest */ + +{ "bte", 0x58000000, 0xa4000000, "1,2,r", 0 }, /* bte isrc1s,isrc2,sbroff */ +{ "bte", 0x5c000000, 0xa0000000, "5,2,r", 0 }, /* bte #const5,isrc2,sbroff */ +{ "btne", 0x50000000, 0xac000000, "1,2,r", 0 }, /* btne isrc1s,isrc2,sbroff */ +{ "btne", 0x54000000, 0xa8000000, "5,2,r", 0 }, /* btne #const5,isrc2,sbroff */ +{ "bla", 0xb4000000, 0x48000000, "1,2,r", E_DELAY }, /* bla isrc1s,isrc2,sbroff */ +{ "bri", 0x40000000, 0xbc000000, "1", E_DELAY }, /* bri isrc1ni */ + +/* Core Escape Instruction Format */ +{ "lock", 0x4c000001, 0xb000001e, "", 0 }, /* lock set BL in dirbase */ +{ "calli", 0x4c000002, 0xb000001d, "1", E_DELAY }, /* calli isrc1ni */ +{ "intovr", 0x4c000004, 0xb000001b, "", 0 }, /* intovr trap on integer overflow */ +{ "unlock", 0x4c000007, 0xb0000018, "", 0 }, /* unlock clear BL in dirbase */ +{ "ldio.l", 0x4c000408, 0xb00003f7, "2,d", XP_ONLY }, /* ldio.l isrc2,idest */ +{ "ldio.s", 0x4c000208, 0xb00005f7, "2,d", XP_ONLY }, /* ldio.s isrc2,idest */ +{ "ldio.b", 0x4c000008, 0xb00007f7, "2,d", XP_ONLY }, /* ldio.b isrc2,idest */ +{ "stio.l", 0x4c000409, 0xb00003f6, "1,2", XP_ONLY }, /* stio.l isrc1ni,isrc2 */ +{ "stio.s", 0x4c000209, 0xb00005f6, "1,2", XP_ONLY }, /* stio.s isrc1ni,isrc2 */ +{ "stio.b", 0x4c000009, 0xb00007f6, "1,2", XP_ONLY }, /* stio.b isrc1ni,isrc2 */ +{ "ldint.l", 0x4c00040a, 0xb00003f5, "2,d", XP_ONLY }, /* ldint.l isrc2,idest */ +{ "ldint.s", 0x4c00020a, 0xb00005f5, "2,d", XP_ONLY }, /* ldint.s isrc2,idest */ +{ "ldint.b", 0x4c00000a, 0xb00007f5, "2,d", XP_ONLY }, /* ldint.b isrc2,idest */ +{ "scyc.b", 0x4c00000b, 0xb00007f4, "2", XP_ONLY }, /* scyc.b isrc2 */ + +/* CTRL-Format Instructions */ +{ "br", 0x68000000, 0x94000000, "l", E_DELAY }, /* br lbroff */ +{ "call", 0x6c000000, 0x90000000, "l", E_DELAY }, /* call lbroff */ +{ "bc", 0x70000000, 0x8c000000, "l", 0 }, /* bc lbroff */ +{ "bc.t", 0x74000000, 0x88000000, "l", E_DELAY }, /* bc.t lbroff */ +{ "bnc", 0x78000000, 0x84000000, "l", 0 }, /* bnc lbroff */ +{ "bnc.t", 0x7c000000, 0x80000000, "l", E_DELAY }, /* bnc.t lbroff */ + +/* Floating Point Escape Instruction Format - pfam.p fsrc1,fsrc2,fdest. */ +{ "r2p1.ss", 0x48000400, 0xb40001ff, "e,f,g", 0 }, +{ "r2p1.sd", 0x48000480, 0xb400017f, "e,f,g", 0 }, +{ "r2p1.dd", 0x48000580, 0xb400007f, "e,f,g", 0 }, +{ "r2pt.ss", 0x48000401, 0xb40001fe, "e,f,g", 0 }, +{ "r2pt.sd", 0x48000481, 0xb400017e, "e,f,g", 0 }, +{ "r2pt.dd", 0x48000581, 0xb400007e, "e,f,g", 0 }, +{ "r2ap1.ss", 0x48000402, 0xb40001fd, "e,f,g", 0 }, +{ "r2ap1.sd", 0x48000482, 0xb400017d, "e,f,g", 0 }, +{ "r2ap1.dd", 0x48000582, 0xb400007d, "e,f,g", 0 }, +{ "r2apt.ss", 0x48000403, 0xb40001fc, "e,f,g", 0 }, +{ "r2apt.sd", 0x48000483, 0xb400017c, "e,f,g", 0 }, +{ "r2apt.dd", 0x48000583, 0xb400007c, "e,f,g", 0 }, +{ "i2p1.ss", 0x48000404, 0xb40001fb, "e,f,g", 0 }, +{ "i2p1.sd", 0x48000484, 0xb400017b, "e,f,g", 0 }, +{ "i2p1.dd", 0x48000584, 0xb400007b, "e,f,g", 0 }, +{ "i2pt.ss", 0x48000405, 0xb40001fa, "e,f,g", 0 }, +{ "i2pt.sd", 0x48000485, 0xb400017a, "e,f,g", 0 }, +{ "i2pt.dd", 0x48000585, 0xb400007a, "e,f,g", 0 }, +{ "i2ap1.ss", 0x48000406, 0xb40001f9, "e,f,g", 0 }, +{ "i2ap1.sd", 0x48000486, 0xb4000179, "e,f,g", 0 }, +{ "i2ap1.dd", 0x48000586, 0xb4000079, "e,f,g", 0 }, +{ "i2apt.ss", 0x48000407, 0xb40001f8, "e,f,g", 0 }, +{ "i2apt.sd", 0x48000487, 0xb4000178, "e,f,g", 0 }, +{ "i2apt.dd", 0x48000587, 0xb4000078, "e,f,g", 0 }, +{ "rat1p2.ss", 0x48000408, 0xb40001f7, "e,f,g", 0 }, +{ "rat1p2.sd", 0x48000488, 0xb4000177, "e,f,g", 0 }, +{ "rat1p2.dd", 0x48000588, 0xb4000077, "e,f,g", 0 }, +{ "m12apm.ss", 0x48000409, 0xb40001f6, "e,f,g", 0 }, +{ "m12apm.sd", 0x48000489, 0xb4000176, "e,f,g", 0 }, +{ "m12apm.dd", 0x48000589, 0xb4000076, "e,f,g", 0 }, +{ "ra1p2.ss", 0x4800040a, 0xb40001f5, "e,f,g", 0 }, +{ "ra1p2.sd", 0x4800048a, 0xb4000175, "e,f,g", 0 }, +{ "ra1p2.dd", 0x4800058a, 0xb4000075, "e,f,g", 0 }, +{ "m12ttpa.ss", 0x4800040b, 0xb40001f4, "e,f,g", 0 }, +{ "m12ttpa.sd", 0x4800048b, 0xb4000174, "e,f,g", 0 }, +{ "m12ttpa.dd", 0x4800058b, 0xb4000074, "e,f,g", 0 }, +{ "iat1p2.ss", 0x4800040c, 0xb40001f3, "e,f,g", 0 }, +{ "iat1p2.sd", 0x4800048c, 0xb4000173, "e,f,g", 0 }, +{ "iat1p2.dd", 0x4800058c, 0xb4000073, "e,f,g", 0 }, +{ "m12tpm.ss", 0x4800040d, 0xb40001f2, "e,f,g", 0 }, +{ "m12tpm.sd", 0x4800048d, 0xb4000172, "e,f,g", 0 }, +{ "m12tpm.dd", 0x4800058d, 0xb4000072, "e,f,g", 0 }, +{ "ia1p2.ss", 0x4800040e, 0xb40001f1, "e,f,g", 0 }, +{ "ia1p2.sd", 0x4800048e, 0xb4000171, "e,f,g", 0 }, +{ "ia1p2.dd", 0x4800058e, 0xb4000071, "e,f,g", 0 }, +{ "m12tpa.ss", 0x4800040f, 0xb40001f0, "e,f,g", 0 }, +{ "m12tpa.sd", 0x4800048f, 0xb4000170, "e,f,g", 0 }, +{ "m12tpa.dd", 0x4800058f, 0xb4000070, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfsm.p fsrc1,fsrc2,fdest. */ +{ "r2s1.ss", 0x48000410, 0xb40001ef, "e,f,g", 0 }, +{ "r2s1.sd", 0x48000490, 0xb400016f, "e,f,g", 0 }, +{ "r2s1.dd", 0x48000590, 0xb400006f, "e,f,g", 0 }, +{ "r2st.ss", 0x48000411, 0xb40001ee, "e,f,g", 0 }, +{ "r2st.sd", 0x48000491, 0xb400016e, "e,f,g", 0 }, +{ "r2st.dd", 0x48000591, 0xb400006e, "e,f,g", 0 }, +{ "r2as1.ss", 0x48000412, 0xb40001ed, "e,f,g", 0 }, +{ "r2as1.sd", 0x48000492, 0xb400016d, "e,f,g", 0 }, +{ "r2as1.dd", 0x48000592, 0xb400006d, "e,f,g", 0 }, +{ "r2ast.ss", 0x48000413, 0xb40001ec, "e,f,g", 0 }, +{ "r2ast.sd", 0x48000493, 0xb400016c, "e,f,g", 0 }, +{ "r2ast.dd", 0x48000593, 0xb400006c, "e,f,g", 0 }, +{ "i2s1.ss", 0x48000414, 0xb40001eb, "e,f,g", 0 }, +{ "i2s1.sd", 0x48000494, 0xb400016b, "e,f,g", 0 }, +{ "i2s1.dd", 0x48000594, 0xb400006b, "e,f,g", 0 }, +{ "i2st.ss", 0x48000415, 0xb40001ea, "e,f,g", 0 }, +{ "i2st.sd", 0x48000495, 0xb400016a, "e,f,g", 0 }, +{ "i2st.dd", 0x48000595, 0xb400006a, "e,f,g", 0 }, +{ "i2as1.ss", 0x48000416, 0xb40001e9, "e,f,g", 0 }, +{ "i2as1.sd", 0x48000496, 0xb4000169, "e,f,g", 0 }, +{ "i2as1.dd", 0x48000596, 0xb4000069, "e,f,g", 0 }, +{ "i2ast.ss", 0x48000417, 0xb40001e8, "e,f,g", 0 }, +{ "i2ast.sd", 0x48000497, 0xb4000168, "e,f,g", 0 }, +{ "i2ast.dd", 0x48000597, 0xb4000068, "e,f,g", 0 }, +{ "rat1s2.ss", 0x48000418, 0xb40001e7, "e,f,g", 0 }, +{ "rat1s2.sd", 0x48000498, 0xb4000167, "e,f,g", 0 }, +{ "rat1s2.dd", 0x48000598, 0xb4000067, "e,f,g", 0 }, +{ "m12asm.ss", 0x48000419, 0xb40001e6, "e,f,g", 0 }, +{ "m12asm.sd", 0x48000499, 0xb4000166, "e,f,g", 0 }, +{ "m12asm.dd", 0x48000599, 0xb4000066, "e,f,g", 0 }, +{ "ra1s2.ss", 0x4800041a, 0xb40001e5, "e,f,g", 0 }, +{ "ra1s2.sd", 0x4800049a, 0xb4000165, "e,f,g", 0 }, +{ "ra1s2.dd", 0x4800059a, 0xb4000065, "e,f,g", 0 }, +{ "m12ttsa.ss", 0x4800041b, 0xb40001e4, "e,f,g", 0 }, +{ "m12ttsa.sd", 0x4800049b, 0xb4000164, "e,f,g", 0 }, +{ "m12ttsa.dd", 0x4800059b, 0xb4000064, "e,f,g", 0 }, +{ "iat1s2.ss", 0x4800041c, 0xb40001e3, "e,f,g", 0 }, +{ "iat1s2.sd", 0x4800049c, 0xb4000163, "e,f,g", 0 }, +{ "iat1s2.dd", 0x4800059c, 0xb4000063, "e,f,g", 0 }, +{ "m12tsm.ss", 0x4800041d, 0xb40001e2, "e,f,g", 0 }, +{ "m12tsm.sd", 0x4800049d, 0xb4000162, "e,f,g", 0 }, +{ "m12tsm.dd", 0x4800059d, 0xb4000062, "e,f,g", 0 }, +{ "ia1s2.ss", 0x4800041e, 0xb40001e1, "e,f,g", 0 }, +{ "ia1s2.sd", 0x4800049e, 0xb4000161, "e,f,g", 0 }, +{ "ia1s2.dd", 0x4800059e, 0xb4000061, "e,f,g", 0 }, +{ "m12tsa.ss", 0x4800041f, 0xb40001e0, "e,f,g", 0 }, +{ "m12tsa.sd", 0x4800049f, 0xb4000160, "e,f,g", 0 }, +{ "m12tsa.dd", 0x4800059f, 0xb4000060, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmam.p fsrc1,fsrc2,fdest. */ +{ "mr2p1.ss", 0x48000000, 0xb40005ff, "e,f,g", 0 }, +{ "mr2p1.sd", 0x48000080, 0xb400057f, "e,f,g", 0 }, +{ "mr2p1.dd", 0x48000180, 0xb400047f, "e,f,g", 0 }, +{ "mr2pt.ss", 0x48000001, 0xb40005fe, "e,f,g", 0 }, +{ "mr2pt.sd", 0x48000081, 0xb400057e, "e,f,g", 0 }, +{ "mr2pt.dd", 0x48000181, 0xb400047e, "e,f,g", 0 }, +{ "mr2mp1.ss", 0x48000002, 0xb40005fd, "e,f,g", 0 }, +{ "mr2mp1.sd", 0x48000082, 0xb400057d, "e,f,g", 0 }, +{ "mr2mp1.dd", 0x48000182, 0xb400047d, "e,f,g", 0 }, +{ "mr2mpt.ss", 0x48000003, 0xb40005fc, "e,f,g", 0 }, +{ "mr2mpt.sd", 0x48000083, 0xb400057c, "e,f,g", 0 }, +{ "mr2mpt.dd", 0x48000183, 0xb400047c, "e,f,g", 0 }, +{ "mi2p1.ss", 0x48000004, 0xb40005fb, "e,f,g", 0 }, +{ "mi2p1.sd", 0x48000084, 0xb400057b, "e,f,g", 0 }, +{ "mi2p1.dd", 0x48000184, 0xb400047b, "e,f,g", 0 }, +{ "mi2pt.ss", 0x48000005, 0xb40005fa, "e,f,g", 0 }, +{ "mi2pt.sd", 0x48000085, 0xb400057a, "e,f,g", 0 }, +{ "mi2pt.dd", 0x48000185, 0xb400047a, "e,f,g", 0 }, +{ "mi2mp1.ss", 0x48000006, 0xb40005f9, "e,f,g", 0 }, +{ "mi2mp1.sd", 0x48000086, 0xb4000579, "e,f,g", 0 }, +{ "mi2mp1.dd", 0x48000186, 0xb4000479, "e,f,g", 0 }, +{ "mi2mpt.ss", 0x48000007, 0xb40005f8, "e,f,g", 0 }, +{ "mi2mpt.sd", 0x48000087, 0xb4000578, "e,f,g", 0 }, +{ "mi2mpt.dd", 0x48000187, 0xb4000478, "e,f,g", 0 }, +{ "mrmt1p2.ss", 0x48000008, 0xb40005f7, "e,f,g", 0 }, +{ "mrmt1p2.sd", 0x48000088, 0xb4000577, "e,f,g", 0 }, +{ "mrmt1p2.dd", 0x48000188, 0xb4000477, "e,f,g", 0 }, +{ "mm12mpm.ss", 0x48000009, 0xb40005f6, "e,f,g", 0 }, +{ "mm12mpm.sd", 0x48000089, 0xb4000576, "e,f,g", 0 }, +{ "mm12mpm.dd", 0x48000189, 0xb4000476, "e,f,g", 0 }, +{ "mrm1p2.ss", 0x4800000a, 0xb40005f5, "e,f,g", 0 }, +{ "mrm1p2.sd", 0x4800008a, 0xb4000575, "e,f,g", 0 }, +{ "mrm1p2.dd", 0x4800018a, 0xb4000475, "e,f,g", 0 }, +{ "mm12ttpm.ss",0x4800000b, 0xb40005f4, "e,f,g", 0 }, +{ "mm12ttpm.sd",0x4800008b, 0xb4000574, "e,f,g", 0 }, +{ "mm12ttpm.dd",0x4800018b, 0xb4000474, "e,f,g", 0 }, +{ "mimt1p2.ss", 0x4800000c, 0xb40005f3, "e,f,g", 0 }, +{ "mimt1p2.sd", 0x4800008c, 0xb4000573, "e,f,g", 0 }, +{ "mimt1p2.dd", 0x4800018c, 0xb4000473, "e,f,g", 0 }, +{ "mm12tpm.ss", 0x4800000d, 0xb40005f2, "e,f,g", 0 }, +{ "mm12tpm.sd", 0x4800008d, 0xb4000572, "e,f,g", 0 }, +{ "mm12tpm.dd", 0x4800018d, 0xb4000472, "e,f,g", 0 }, +{ "mim1p2.ss", 0x4800000e, 0xb40005f1, "e,f,g", 0 }, +{ "mim1p2.sd", 0x4800008e, 0xb4000571, "e,f,g", 0 }, +{ "mim1p2.dd", 0x4800018e, 0xb4000471, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmsm.p fsrc1,fsrc2,fdest. */ +{ "mr2s1.ss", 0x48000010, 0xb40005ef, "e,f,g", 0 }, +{ "mr2s1.sd", 0x48000090, 0xb400056f, "e,f,g", 0 }, +{ "mr2s1.dd", 0x48000190, 0xb400046f, "e,f,g", 0 }, +{ "mr2st.ss", 0x48000011, 0xb40005ee, "e,f,g", 0 }, +{ "mr2st.sd", 0x48000091, 0xb400056e, "e,f,g", 0 }, +{ "mr2st.dd", 0x48000191, 0xb400046e, "e,f,g", 0 }, +{ "mr2ms1.ss", 0x48000012, 0xb40005ed, "e,f,g", 0 }, +{ "mr2ms1.sd", 0x48000092, 0xb400056d, "e,f,g", 0 }, +{ "mr2ms1.dd", 0x48000192, 0xb400046d, "e,f,g", 0 }, +{ "mr2mst.ss", 0x48000013, 0xb40005ec, "e,f,g", 0 }, +{ "mr2mst.sd", 0x48000093, 0xb400056c, "e,f,g", 0 }, +{ "mr2mst.dd", 0x48000193, 0xb400046c, "e,f,g", 0 }, +{ "mi2s1.ss", 0x48000014, 0xb40005eb, "e,f,g", 0 }, +{ "mi2s1.sd", 0x48000094, 0xb400056b, "e,f,g", 0 }, +{ "mi2s1.dd", 0x48000194, 0xb400046b, "e,f,g", 0 }, +{ "mi2st.ss", 0x48000015, 0xb40005ea, "e,f,g", 0 }, +{ "mi2st.sd", 0x48000095, 0xb400056a, "e,f,g", 0 }, +{ "mi2st.dd", 0x48000195, 0xb400046a, "e,f,g", 0 }, +{ "mi2ms1.ss", 0x48000016, 0xb40005e9, "e,f,g", 0 }, +{ "mi2ms1.sd", 0x48000096, 0xb4000569, "e,f,g", 0 }, +{ "mi2ms1.dd", 0x48000196, 0xb4000469, "e,f,g", 0 }, +{ "mi2mst.ss", 0x48000017, 0xb40005e8, "e,f,g", 0 }, +{ "mi2mst.sd", 0x48000097, 0xb4000568, "e,f,g", 0 }, +{ "mi2mst.dd", 0x48000197, 0xb4000468, "e,f,g", 0 }, +{ "mrmt1s2.ss", 0x48000018, 0xb40005e7, "e,f,g", 0 }, +{ "mrmt1s2.sd", 0x48000098, 0xb4000567, "e,f,g", 0 }, +{ "mrmt1s2.dd", 0x48000198, 0xb4000467, "e,f,g", 0 }, +{ "mm12msm.ss", 0x48000019, 0xb40005e6, "e,f,g", 0 }, +{ "mm12msm.sd", 0x48000099, 0xb4000566, "e,f,g", 0 }, +{ "mm12msm.dd", 0x48000199, 0xb4000466, "e,f,g", 0 }, +{ "mrm1s2.ss", 0x4800001a, 0xb40005e5, "e,f,g", 0 }, +{ "mrm1s2.sd", 0x4800009a, 0xb4000565, "e,f,g", 0 }, +{ "mrm1s2.dd", 0x4800019a, 0xb4000465, "e,f,g", 0 }, +{ "mm12ttsm.ss",0x4800001b, 0xb40005e4, "e,f,g", 0 }, +{ "mm12ttsm.sd",0x4800009b, 0xb4000564, "e,f,g", 0 }, +{ "mm12ttsm.dd",0x4800019b, 0xb4000464, "e,f,g", 0 }, +{ "mimt1s2.ss", 0x4800001c, 0xb40005e3, "e,f,g", 0 }, +{ "mimt1s2.sd", 0x4800009c, 0xb4000563, "e,f,g", 0 }, +{ "mimt1s2.dd", 0x4800019c, 0xb4000463, "e,f,g", 0 }, +{ "mm12tsm.ss", 0x4800001d, 0xb40005e2, "e,f,g", 0 }, +{ "mm12tsm.sd", 0x4800009d, 0xb4000562, "e,f,g", 0 }, +{ "mm12tsm.dd", 0x4800019d, 0xb4000462, "e,f,g", 0 }, +{ "mim1s2.ss", 0x4800001e, 0xb40005e1, "e,f,g", 0 }, +{ "mim1s2.sd", 0x4800009e, 0xb4000561, "e,f,g", 0 }, +{ "mim1s2.dd", 0x4800019e, 0xb4000461, "e,f,g", 0 }, + +{ "fmul.ss", 0x48000020, 0xb40005df, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.sd", 0x480000a0, 0xb400055f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.dd", 0x480001a0, 0xb400045f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.ss", 0x48000420, 0xb40001df, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.sd", 0x480004a0, 0xb400015f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.dd", 0x480005a0, 0xb400005f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul3.dd", 0x480005a4, 0xb400005b, "e,f,g", 0 }, /* pfmul3.p fsrc1,fsrc2,fdest */ +{ "fmlow.dd", 0x480001a1, 0xb400045e, "e,f,g", 0 }, /* fmlow.dd fsrc1,fsrc2,fdest */ +{ "frcp.ss", 0x48000022, 0xb40005dd, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.sd", 0x480000a2, 0xb400055d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.dd", 0x480001a2, 0xb400045d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frsqr.ss", 0x48000023, 0xb40005dc, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.sd", 0x480000a3, 0xb400055c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.dd", 0x480001a3, 0xb400045c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "fadd.ss", 0x48000030, 0xb40005cf, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.sd", 0x480000b0, 0xb400054f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.dd", 0x480001b0, 0xb400044f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.ss", 0x48000430, 0xb40001cf, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.sd", 0x480004b0, 0xb400014f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.dd", 0x480005b0, 0xb400004f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "fsub.ss", 0x48000031, 0xb40005ce, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.sd", 0x480000b1, 0xb400054e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.dd", 0x480001b1, 0xb400044e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.ss", 0x48000431, 0xb40001ce, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.sd", 0x480004b1, 0xb400014e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.dd", 0x480005b1, 0xb400004e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "fix.sd", 0x480000b2, 0xb400054d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "fix.dd", 0x480001b2, 0xb400044d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "pfix.sd", 0x480004b2, 0xb400014d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "pfix.dd", 0x480005b2, 0xb400004d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "famov.ss", 0x48000033, 0xb40005cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.ds", 0x48000133, 0xb40004cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.sd", 0x480000b3, 0xb400054c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.dd", 0x480001b3, 0xb400044c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "pfamov.ss", 0x48000433, 0xb40001cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.ds", 0x48000533, 0xb40000cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.sd", 0x480004b3, 0xb400014c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.dd", 0x480005b3, 0xb400004c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +/* Opcode pfgt has R bit cleared; pfle has R bit set. */ +{ "pfgt.ss", 0x48000434, 0xb40001cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +{ "pfgt.dd", 0x48000534, 0xb40000cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +/* Opcode pfgt has R bit cleared; pfle has R bit set. */ +{ "pfle.ss", 0x480004b4, 0xb400014b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfle.dd", 0x480005b4, 0xb400004b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfeq.ss", 0x48000435, 0xb40001ca, "e,f,g", 0 }, /* pfeq.p fsrc1,fsrc2,fdest */ +{ "pfeq.dd", 0x48000535, 0xb40000ca, "e,f,g", 0 }, /* pfeq.p fsrc1,fsrc2,fdest */ +{ "ftrunc.sd", 0x480000ba, 0xb4000545, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "ftrunc.dd", 0x480001ba, 0xb4000445, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "pftrunc.sd", 0x480004ba, 0xb4000145, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "pftrunc.dd", 0x480005ba, 0xb4000045, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "fxfr", 0x48000040, 0xb40005bf, "e,d", 0 }, /* fxfr fsrc1,idest */ +{ "fiadd.ss", 0x48000049, 0xb40005b6, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "fiadd.dd", 0x480001c9, 0xb4000436, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.ss", 0x48000449, 0xb40001b6, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.dd", 0x480005c9, 0xb4000036, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "fisub.ss", 0x4800004d, 0xb40005b2, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "fisub.dd", 0x480001cd, 0xb4000432, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.ss", 0x4800044d, 0xb40001b2, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.dd", 0x480005cd, 0xb4000032, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "fzchkl", 0x480001d7, 0xb4000428, "e,f,g", 0 }, /* fzchkl fsrc1,fsrc2,fdest */ +{ "pfzchkl", 0x480005d7, 0xb4000028, "e,f,g", 0 }, /* pfzchkl fsrc1,fsrc2,fdest */ +{ "fzchks", 0x480001df, 0xb4000420, "e,f,g", 0 }, /* fzchks fsrc1,fsrc2,fdest */ +{ "pfzchks", 0x480005df, 0xb4000020, "e,f,g", 0 }, /* pfzchks fsrc1,fsrc2,fdest */ +{ "faddp", 0x480001d0, 0xb400042f, "e,f,g", 0 }, /* faddp fsrc1,fsrc2,fdest */ +{ "pfaddp", 0x480005d0, 0xb400002f, "e,f,g", 0 }, /* pfaddp fsrc1,fsrc2,fdest */ +{ "faddz", 0x480001d1, 0xb400042e, "e,f,g", 0 }, /* faddz fsrc1,fsrc2,fdest */ +{ "pfaddz", 0x480005d1, 0xb400002e, "e,f,g", 0 }, /* pfaddz fsrc1,fsrc2,fdest */ +{ "form", 0x480001da, 0xb4000425, "e,g", 0 }, /* form fsrc1,fdest */ +{ "pform", 0x480005da, 0xb4000025, "e,g", 0 }, /* pform fsrc1,fdest */ + +/* Floating point pseudo-instructions. */ +{ "fmov.ss", 0x48000049, 0xb7e005b6, "e,g", 0 }, /* fiadd.ss fsrc1,f0,fdest */ +{ "fmov.dd", 0x480001c9, 0xb7e00436, "e,g", 0 }, /* fiadd.dd fsrc1,f0,fdest */ +{ "fmov.sd", 0x480000b3, 0xb400054c, "e,g", 0 }, /* famov.sd fsrc1,fdest */ +{ "fmov.ds", 0x48000133, 0xb40004cc, "e,g", 0 }, /* famov.ds fsrc1,fdest */ +{ "pfmov.ds", 0x48000533, 0xb40000cc, "e,g", 0 }, /* pfamov.ds fsrc1,fdest */ +{ "pfmov.dd", 0x480005c9, 0xb7e00036, "e,g", 0 }, /* pfiadd.dd fsrc1,f0,fdest */ +{ 0, 0, 0, 0, 0 }, + +}; + +#define NUMOPCODES ((sizeof i860_opcodes)/(sizeof i860_opcodes[0])) + + diff --git a/ld/Makefile.am b/ld/Makefile.am index 3ae3d7f14f6..54bc38dcd2c 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to generate Makefile.in # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -214,6 +215,7 @@ ALL_EMULATION_SOURCES = \ ed30v_o.c \ ed30velf.c \ eelf32_dlx.c \ + eelf32_i860.c \ eelf32_sparc.c \ eelf32_sparc_sol2.c \ eelf32_sparc_vxworks.c \ diff --git a/ld/Makefile.in b/ld/Makefile.in index d879f04a17c..99b8f53c3d2 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -729,6 +729,7 @@ ALL_EMULATION_SOURCES = \ ed30v_o.c \ ed30velf.c \ eelf32_dlx.c \ + eelf32_i860.c \ eelf32_sparc.c \ eelf32_sparc_sol2.c \ eelf32_sparc_vxworks.c \ @@ -1339,6 +1340,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ed30v_o.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ed30velf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32_dlx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32_i860.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32_sparc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32_sparc_sol2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32_sparc_vxworks.Po@am__quote@ diff --git a/ld/configure.tgt b/ld/configure.tgt index 60b62e69c08..8dad857967c 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -1,6 +1,7 @@ # configure.tgt # # Copyright (C) 2013-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -70,7 +71,9 @@ if test "${ac_default_ld_warn_execstack}" = 2; then # The HPPA port needs to support older kernels that # use executable stacks for signals and syscalls. # Many MIPS targets use executable stacks. + # The i860 MMU has no execute permission for an executable stack to add. hppa*-*-* | \ + i860-*-* | \ mips*-*-*) ac_default_ld_warn_execstack=0 ;; @@ -428,6 +431,9 @@ i[3-7]86-*-chaos) targ_emul=elf_i386_chaos ia16-*-elf*) targ_emul=elf_i386 targ_extra_emuls=i386msdos ;; +i860-stardent-sysv4* | i860-stardent-elf* | i860-*-linux*) + targ_emul=elf32_i860 + ;; ia64-*-elf*) targ_emul=elf64_ia64 ;; ia64-*-freebsd* | ia64-*-kfreebsd*-gnu) diff --git a/ld/emulparams/elf32_i860.sh b/ld/emulparams/elf32_i860.sh new file mode 100644 index 00000000000..a3803ac6a3d --- /dev/null +++ b/ld/emulparams/elf32_i860.sh @@ -0,0 +1,24 @@ +# A work in progress... +# Copyright (C) 2026 René Rebe +SCRIPT_NAME=elf +TEMPLATE_NAME=generic +EXTRA_EM_FILE=genelf +OUTPUT_FORMAT="elf32-i860-little" +BIG_OUTPUT_FORMAT="elf32-i860" +LITTLE_OUTPUT_FORMAT="elf32-i860-little" +NO_REL_RELOCS=yes +TEXT_START_ADDR=0 +PAGE_SIZE=0x1000 +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" +ARCH=i860 + +case "$target" in + i860-*-linux*) + TEMPLATE_NAME=elf + EXTRA_EM_FILE= + TEXT_START_ADDR=0x10000 + GENERATE_SHLIB_SCRIPT=yes + GENERATE_PIE_SCRIPT=yes + COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" + ;; +esac diff --git a/ld/po/BLD-POTFILES.in b/ld/po/BLD-POTFILES.in index d7d0c517307..02ccedbb5dc 100644 --- a/ld/po/BLD-POTFILES.in +++ b/ld/po/BLD-POTFILES.in @@ -73,6 +73,7 @@ ed30v_e.c ed30v_o.c ed30velf.c eelf32_dlx.c +eelf32_i860.c eelf32_sparc.c eelf32_sparc_sol2.c eelf32_sparc_vxworks.c diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index a0fcf4d5ec7..3ebdb6266ba 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to generate Makefile.in # # Copyright (C) 2012-2026 Free Software Foundation, Inc. +# Copyright (C) 2026 René Rebe # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -156,6 +157,7 @@ TARGET32_LIBOPCODES_CFILES = \ h8300-dis.c \ hppa-dis.c \ i386-dis.c \ + i860-dis.c \ ip2k-asm.c \ ip2k-desc.c \ ip2k-dis.c \ diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index c5449bebf54..7b5c6c22bfd 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -562,6 +562,7 @@ TARGET32_LIBOPCODES_CFILES = \ h8300-dis.c \ hppa-dis.c \ i386-dis.c \ + i860-dis.c \ ip2k-asm.c \ ip2k-desc.c \ ip2k-dis.c \ @@ -933,6 +934,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/h8300-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hppa-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i860-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia64-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia64-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip2k-asm.Plo@am__quote@ diff --git a/opcodes/configure b/opcodes/configure index 8299ef7e995..72027a84bc6 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -14345,6 +14345,7 @@ if test x${all_targets} = xfalse ; then bfd_hppa_arch) ta="$ta hppa-dis.lo" ;; bfd_i386_arch|bfd_iamcu_arch) ta="$ta i386-dis.lo" ;; + bfd_i860_arch) ta="$ta i860-dis.lo" ;; bfd_ia64_arch) ta="$ta ia64-dis.lo ia64-opc.lo" ;; bfd_ip2k_arch) ta="$ta ip2k-asm.lo ip2k-desc.lo ip2k-dis.lo ip2k-ibld.lo ip2k-opc.lo" using_cgen=yes ;; bfd_epiphany_arch) ta="$ta epiphany-asm.lo epiphany-desc.lo epiphany-dis.lo epiphany-ibld.lo epiphany-opc.lo" using_cgen=yes ;; diff --git a/opcodes/configure.ac b/opcodes/configure.ac index 2c2556598c9..d9ea67b9209 100644 --- a/opcodes/configure.ac +++ b/opcodes/configure.ac @@ -1,6 +1,7 @@ dnl Process this file with autoconf to produce a configure script. dnl dnl Copyright (C) 2012-2026 Free Software Foundation, Inc. +dnl Copyright (C) 2026 René Rebe dnl dnl This file is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -284,6 +285,7 @@ if test x${all_targets} = xfalse ; then bfd_hppa_arch) ta="$ta hppa-dis.lo" ;; bfd_i386_arch|bfd_iamcu_arch) ta="$ta i386-dis.lo" ;; + bfd_i860_arch) ta="$ta i860-dis.lo" ;; bfd_ia64_arch) ta="$ta ia64-dis.lo ia64-opc.lo" ;; bfd_ip2k_arch) ta="$ta ip2k-asm.lo ip2k-desc.lo ip2k-dis.lo ip2k-ibld.lo ip2k-opc.lo" using_cgen=yes ;; bfd_epiphany_arch) ta="$ta epiphany-asm.lo epiphany-desc.lo epiphany-dis.lo epiphany-ibld.lo epiphany-opc.lo" using_cgen=yes ;; diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index 77d44bb08db..da971e29ee4 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -1,5 +1,6 @@ /* Select disassembly routine for specified architecture. Copyright (C) 1994-2026 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe This file is part of the GNU opcodes library. @@ -55,6 +56,7 @@ #define ARCH_h8300 #define ARCH_hppa #define ARCH_i386 +#define ARCH_i860 #define ARCH_ip2k #define ARCH_iq2000 #define ARCH_kvx @@ -214,6 +216,11 @@ disassembler (enum bfd_architecture a, disassemble = print_insn_i386; break; #endif +#ifdef ARCH_i860 + case bfd_arch_i860: + disassemble = print_insn_i860; + break; +#endif #ifdef ARCH_ia64 case bfd_arch_ia64: disassemble = print_insn_ia64; diff --git a/opcodes/disassemble.h b/opcodes/disassemble.h index 2157790c947..1be675289d4 100644 --- a/opcodes/disassemble.h +++ b/opcodes/disassemble.h @@ -1,6 +1,7 @@ /* Header only used inside opcodes library for disassemble. Copyright (C) 2017-2026 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe 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 @@ -47,6 +48,7 @@ extern int print_insn_hppa (bfd_vma, disassemble_info *); extern int print_insn_i386 (bfd_vma, disassemble_info *); extern int print_insn_i386_att (bfd_vma, disassemble_info *); extern int print_insn_i386_intel (bfd_vma, disassemble_info *); +extern int print_insn_i860 (bfd_vma, disassemble_info *); extern int print_insn_ia64 (bfd_vma, disassemble_info *); extern int print_insn_ip2k (bfd_vma, disassemble_info *); extern int print_insn_iq2000 (bfd_vma, disassemble_info *); diff --git a/opcodes/i860-dis.c b/opcodes/i860-dis.c new file mode 100644 index 00000000000..ab1136e9c89 --- /dev/null +++ b/opcodes/i860-dis.c @@ -0,0 +1,287 @@ +/* Disassembler for the i860. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + Copyright (C) 2026 René Rebe + + Contributed by Jason Eckhardt . + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "disassemble.h" +#include "opcode/i860.h" + +/* Later we should probably choose the prefix based on which OS flavor. */ +#define I860_REG_PREFIX "%" + +/* Integer register names (encoded as 0..31 in the instruction). */ +static const char *const grnames[] = + {"r0", "r1", "sp", "fp", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; + +/* FP register names (encoded as 0..31 in the instruction). */ +static const char *const frnames[] = + {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; + +/* Control/status register names (encoded as 0..11 in the instruction). + Registers bear, ccr, p0, p1, p2 and p3 are XP only. */ +static const char *const crnames[] = + {"fir", "psr", "dirbase", "db", "fsr", "epsr", "bear", "ccr", + "p0", "p1", "p2", "p3", "--", "--", "--", "--" }; + + + +/* True if opcode is xor, xorh, and, andh, or, orh, andnot, andnoth. */ +#define BITWISE_OP(op) ((op) == 0x30 || (op) == 0x31 \ + || (op) == 0x34 || (op) == 0x35 \ + || (op) == 0x38 || (op) == 0x39 \ + || (op) == 0x3c || (op) == 0x3d \ + || (op) == 0x33 || (op) == 0x37 \ + || (op) == 0x3b || (op) == 0x3f) + + +/* Sign extend N-bit number. */ +static int +sign_ext (unsigned int x, int n) +{ + int t; + t = x >> (n - 1); + t = ((-t) << n) | x; + return t; +} + + +/* Print a PC-relative branch offset. VAL is the sign extended value + from the branch instruction. */ +static void +print_br_address (disassemble_info *info, bfd_vma memaddr, long val) +{ + + long adj = (long)memaddr + 4 + (val << 2); + + (*info->fprintf_func) (info->stream, "0x%08lx", adj); + + /* Attempt to obtain a symbol for the target address. */ + + if (info->print_address_func && adj != 0) + { + (*info->fprintf_func) (info->stream, "\t// "); + (*info->print_address_func) (adj, info); + } +} + + +/* Print one instruction. */ +int +print_insn_i860 (bfd_vma memaddr, disassemble_info *info) +{ + bfd_byte buff[4]; + unsigned int insn, i; + int status; + const struct i860_opcode *opcode = 0; + + status = (*info->read_memory_func) (memaddr, buff, sizeof (buff), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + /* Note that i860 instructions are always accessed as little endian + data, regardless of the endian mode of the i860. */ + insn = bfd_getl32 (buff); + + status = 0; + i = 0; + while (i860_opcodes[i].name != NULL) + { + opcode = &i860_opcodes[i]; + if ((insn & opcode->match) == opcode->match + && (insn & opcode->lose) == 0) + { + status = 1; + break; + } + ++i; + } + + if (status == 0) + { + /* Instruction not in opcode table. */ + (*info->fprintf_func) (info->stream, ".long %#08x", insn); + } + else + { + const char *s; + int val; + + /* If this a flop (or a shrd) and its dual bit is set, + prefix with 'd.'. */ + if (((insn & 0xfc000000) == 0x48000000 + || (insn & 0xfc000000) == 0xb0000000) + && (insn & 0x200)) + (*info->fprintf_func) (info->stream, "d.%s\t", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s\t", opcode->name); + + for (s = opcode->args; *s; s++) + { + switch (*s) + { + /* Integer register (src1). */ + case '1': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 11) & 0x1f]); + break; + + /* Integer register (src2). */ + case '2': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 21) & 0x1f]); + break; + + /* Integer destination register. */ + case 'd': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 16) & 0x1f]); + break; + + /* Floating-point register (src1). */ + case 'e': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 11) & 0x1f]); + break; + + /* Floating-point register (src2). */ + case 'f': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 21) & 0x1f]); + break; + + /* Floating-point destination register. */ + case 'g': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 16) & 0x1f]); + break; + + /* Control register. */ + case 'c': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + crnames[(insn >> 21) & 0xf]); + break; + + /* 16-bit immediate (sign extend, except for bitwise ops). */ + case 'i': + if (BITWISE_OP ((insn & 0xfc000000) >> 26)) + (*info->fprintf_func) (info->stream, "0x%04x", + (unsigned int) (insn & 0xffff)); + else + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xffff), 16)); + break; + + /* 16-bit immediate, aligned (2^0, ld.b). */ + case 'I': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xffff), 16)); + break; + + /* 16-bit immediate, aligned (2^1, ld.s). */ + case 'J': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfffe), 16)); + break; + + /* 16-bit immediate, aligned (2^2, ld.l, {p}fld.l, fst.l). */ + case 'K': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfffc), 16)); + break; + + /* 16-bit immediate, aligned (2^3, {p}fld.d, fst.d). */ + case 'L': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfff8), 16)); + break; + + /* 16-bit immediate, aligned (2^4, {p}fld.q, fst.q). */ + case 'M': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfff0), 16)); + break; + + /* 5-bit immediate (zero extend). */ + case '5': + (*info->fprintf_func) (info->stream, "%d", + ((insn >> 11) & 0x1f)); + break; + + /* Split 16 bit immediate (20..16:10..0). */ + case 's': + val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^0, st.b). */ + case 'S': + val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^1, st.s). */ + case 'T': + val = ((insn >> 5) & 0xf800) | (insn & 0x07fe); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^2, st.l). */ + case 'U': + val = ((insn >> 5) & 0xf800) | (insn & 0x07fc); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* 26-bit PC relative immediate (lbroff). */ + case 'l': + val = sign_ext ((insn & 0x03ffffff), 26); + print_br_address (info, memaddr, val); + break; + + /* 16-bit PC relative immediate (sbroff). */ + case 'r': + val = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + print_br_address (info, memaddr, val); + break; + + default: + (*info->fprintf_func) (info->stream, "%c", *s); + break; + } + } + } + + return sizeof (insn); +} + diff --git a/opcodes/po/POTFILES.in b/opcodes/po/POTFILES.in index c8f83622734..1c4af94e8a5 100644 --- a/opcodes/po/POTFILES.in +++ b/opcodes/po/POTFILES.in @@ -67,6 +67,7 @@ h8300-dis.c hppa-dis.c i386-dis.c i386-opc.h +i860-dis.c ia64-asmtab.h ia64-dis.c ia64-opc.c