diff options
176 files changed, 13183 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4b66949..7565d92 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,32 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * Makefile.am (ALL_MACHINES): Add cpu-nios2.lo. + (ALL_MACHINES_CFILES): Add cpu-nios2.c. + (BFD_BACKENDS): Add elf32-nios2.lo. + (BFD32_BACKENDS_CFILES): Add elf32-nios2.c. + * Makefile.in: Regenerated. + * configure.in: Add entries for bfd_elf32_bignios2_vec and + bfd_elf32_littlenios2_vec. + * configure: Regenerated. + * config.bfd: Add cases for nios2. + * archures.c (enum bfd_architecture): Add bfd_arch_nios2. + (bfd_mach_nios2): Define. + (bfd_nios2_arch): Declare. + (bfd_archures_list): Add bfd_nios2_arch. + * targets.c (bfd_elf32_bignios2_vec): Declare. + (bfd_elf32_littlenios2_vec): Declare. + (_bfd_target_vector): Add entries for bfd_elf32_bignios2_vec and + bfd_elf32_littlenios2_vec. + * elf-bfd.h (enum elf_target_id): Add NIOS2_ELF_DATA. + * reloc.c (enum bfd_reloc_code_real): Add Nios II relocations. + * bfd-in2.h: Regenerated. + * libbfd.h: Regenerated. + * cpu-nios2.c: New file. + * elf32-nios2.c: New file. + 2013-02-06 Alan Modra <amodra@gmail.com> * elf32-arm.c (elf32_arm_final_link_relocate): Only test for diff --git a/bfd/Makefile.am b/bfd/Makefile.am index 8c348f3..6efe20f 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -136,6 +136,7 @@ ALL_MACHINES = \ cpu-moxie.lo \ cpu-msp430.lo \ cpu-mt.lo \ + cpu-nios2.lo \ cpu-ns32k.lo \ cpu-openrisc.lo \ cpu-or32.lo \ @@ -220,6 +221,7 @@ ALL_MACHINES_CFILES = \ cpu-msp430.c \ cpu-mt.c \ cpu-ns32k.c \ + cpu-nios2.c \ cpu-openrisc.c \ cpu-or32.c \ cpu-pdp11.c \ @@ -348,6 +350,7 @@ BFD32_BACKENDS = \ elf32-moxie.lo \ elf32-msp430.lo \ elf32-mt.lo \ + elf32-nios2.lo \ elf32-openrisc.lo \ elf32-or32.lo \ elf32-pj.lo \ @@ -537,6 +540,7 @@ BFD32_BACKENDS_CFILES = \ elf32-moxie.c \ elf32-msp430.c \ elf32-mt.c \ + elf32-nios2.c \ elf32-openrisc.c \ elf32-or32.c \ elf32-pj.c \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index a74aaa1..e54cf57 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -437,6 +437,7 @@ ALL_MACHINES = \ cpu-moxie.lo \ cpu-msp430.lo \ cpu-mt.lo \ + cpu-nios2.lo \ cpu-ns32k.lo \ cpu-openrisc.lo \ cpu-or32.lo \ @@ -521,6 +522,7 @@ ALL_MACHINES_CFILES = \ cpu-msp430.c \ cpu-mt.c \ cpu-ns32k.c \ + cpu-nios2.c \ cpu-openrisc.c \ cpu-or32.c \ cpu-pdp11.c \ @@ -650,6 +652,7 @@ BFD32_BACKENDS = \ elf32-moxie.lo \ elf32-msp430.lo \ elf32-mt.lo \ + elf32-nios2.lo \ elf32-openrisc.lo \ elf32-or32.lo \ elf32-pj.lo \ @@ -839,6 +842,7 @@ BFD32_BACKENDS_CFILES = \ elf32-moxie.c \ elf32-msp430.c \ elf32-mt.c \ + elf32-nios2.c \ elf32-openrisc.c \ elf32-or32.c \ elf32-pj.c \ @@ -1345,6 +1349,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-moxie.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-msp430.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nios2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ns32k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-openrisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-or32.Plo@am__quote@ @@ -1433,6 +1438,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nios2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-openrisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@ diff --git a/bfd/archures.c b/bfd/archures.c index a1b7868..0be72da 100644 --- a/bfd/archures.c +++ b/bfd/archures.c @@ -468,6 +468,8 @@ DESCRIPTION .#define bfd_mach_tilegx32 2 . bfd_arch_aarch64, {* AArch64 *} .#define bfd_mach_aarch64 0 +. bfd_arch_nios2, +.#define bfd_mach_nios2 0 . bfd_arch_last . }; */ @@ -560,6 +562,7 @@ extern const bfd_arch_info_type bfd_mn10300_arch; extern const bfd_arch_info_type bfd_moxie_arch; extern const bfd_arch_info_type bfd_msp430_arch; extern const bfd_arch_info_type bfd_mt_arch; +extern const bfd_arch_info_type bfd_nios2_arch; extern const bfd_arch_info_type bfd_ns32k_arch; extern const bfd_arch_info_type bfd_openrisc_arch; extern const bfd_arch_info_type bfd_or32_arch; @@ -648,6 +651,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_moxie_arch, &bfd_msp430_arch, &bfd_mt_arch, + &bfd_nios2_arch, &bfd_ns32k_arch, &bfd_openrisc_arch, &bfd_or32_arch, diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 5b04176..6dfd17f 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2199,6 +2199,8 @@ enum bfd_architecture #define bfd_mach_tilegx32 2 bfd_arch_aarch64, /* AArch64 */ #define bfd_mach_aarch64 0 + bfd_arch_nios2, +#define bfd_mach_nios2 0 bfd_arch_last }; @@ -4913,6 +4915,42 @@ a matching LO8XG part. */ BFD_RELOC_MSP430_2X_PCREL, BFD_RELOC_MSP430_RL_PCREL, +/* Relocations used by the Altera Nios II core. */ + BFD_RELOC_NIOS2_S16, + BFD_RELOC_NIOS2_U16, + BFD_RELOC_NIOS2_CALL26, + BFD_RELOC_NIOS2_IMM5, + BFD_RELOC_NIOS2_CACHE_OPX, + BFD_RELOC_NIOS2_IMM6, + BFD_RELOC_NIOS2_IMM8, + BFD_RELOC_NIOS2_HI16, + BFD_RELOC_NIOS2_LO16, + BFD_RELOC_NIOS2_HIADJ16, + BFD_RELOC_NIOS2_GPREL, + BFD_RELOC_NIOS2_UJMP, + BFD_RELOC_NIOS2_CJMP, + BFD_RELOC_NIOS2_CALLR, + BFD_RELOC_NIOS2_ALIGN, + BFD_RELOC_NIOS2_GOT16, + BFD_RELOC_NIOS2_CALL16, + BFD_RELOC_NIOS2_GOTOFF_LO, + BFD_RELOC_NIOS2_GOTOFF_HA, + BFD_RELOC_NIOS2_PCREL_LO, + BFD_RELOC_NIOS2_PCREL_HA, + BFD_RELOC_NIOS2_TLS_GD16, + BFD_RELOC_NIOS2_TLS_LDM16, + BFD_RELOC_NIOS2_TLS_LDO16, + BFD_RELOC_NIOS2_TLS_IE16, + BFD_RELOC_NIOS2_TLS_LE16, + BFD_RELOC_NIOS2_TLS_DTPMOD, + BFD_RELOC_NIOS2_TLS_DTPREL, + BFD_RELOC_NIOS2_TLS_TPREL, + BFD_RELOC_NIOS2_COPY, + BFD_RELOC_NIOS2_GLOB_DAT, + BFD_RELOC_NIOS2_JUMP_SLOT, + BFD_RELOC_NIOS2_RELATIVE, + BFD_RELOC_NIOS2_GOTOFF, + /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, BFD_RELOC_IQ2000_OFFSET_21, diff --git a/bfd/config.bfd b/bfd/config.bfd index cd19936..0f75b0b 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -109,6 +109,7 @@ m68*) targ_archs=bfd_m68k_arch ;; m88*) targ_archs=bfd_m88k_arch ;; microblaze*) targ_archs=bfd_microblaze_arch ;; mips*) targ_archs=bfd_mips_arch ;; +nios2*) targ_archs=bfd_nios2_arch ;; or32*) targ_archs=bfd_or32_arch ;; pdp11*) targ_archs=bfd_pdp11_arch ;; pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; @@ -1144,6 +1145,21 @@ case "${targ}" in targ_underscore=yes ;; + nios2eb-*-*) + targ_defvec=bfd_elf32_bignios2_vec + targ_selvecs=bfd_elf32_littlenios2_vec + ;; + + nios2el-*-*) + targ_defvec=bfd_elf32_littlenios2_vec + targ_selvecs=bfd_elf32_bignios2_vec + ;; + + nios2-*-*) + targ_defvec=bfd_elf32_littlenios2_vec + targ_selvecs=bfd_elf32_bignios2_vec + ;; + openrisc-*-elf) targ_defvec=bfd_elf32_openrisc_vec ;; diff --git a/bfd/configure b/bfd/configure index 1279e56..426c18c 100755 --- a/bfd/configure +++ b/bfd/configure @@ -15228,6 +15228,7 @@ do bfd_elf32_bigmips_vxworks_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; bfd_elf32_bigmoxie_vec) tb="$tb elf32-moxie.lo elf32.lo $elf" ;; + bfd_elf32_bignios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_cr16_vec) tb="$tb elf32-cr16.lo elf32.lo $elf" ;; bfd_elf32_cr16c_vec) tb="$tb elf32-cr16c.lo elf32.lo $elf" ;; bfd_elf32_cris_vec) tb="$tb elf32-cris.lo elf32.lo $elf" ;; @@ -15270,6 +15271,7 @@ do bfd_elf32_littlemips_vxworks_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; bfd_elf32_littlemoxie_vec) tb="$tb elf32-moxie.lo elf32.lo $elf" ;; + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_m32c_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; bfd_elf32_m32r_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; bfd_elf32_m32rle_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; diff --git a/bfd/configure.in b/bfd/configure.in index 33f62e3..960dc4e 100644 --- a/bfd/configure.in +++ b/bfd/configure.in @@ -725,6 +725,7 @@ do bfd_elf32_bigmips_vxworks_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; bfd_elf32_bigmoxie_vec) tb="$tb elf32-moxie.lo elf32.lo $elf" ;; + bfd_elf32_bignios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_cr16_vec) tb="$tb elf32-cr16.lo elf32.lo $elf" ;; bfd_elf32_cr16c_vec) tb="$tb elf32-cr16c.lo elf32.lo $elf" ;; bfd_elf32_cris_vec) tb="$tb elf32-cris.lo elf32.lo $elf" ;; @@ -767,6 +768,7 @@ do bfd_elf32_littlemips_vxworks_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; bfd_elf32_littlemoxie_vec) tb="$tb elf32-moxie.lo elf32.lo $elf" ;; + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_m32c_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; bfd_elf32_m32r_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; bfd_elf32_m32rle_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; diff --git a/bfd/cpu-nios2.c b/bfd/cpu-nios2.c new file mode 100644 index 0000000..fa4c859 --- /dev/null +++ b/bfd/cpu-nios2.c @@ -0,0 +1,44 @@ +/* BFD support for the Altera Nios II processor. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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" + +#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ + { \ + BITS_WORD, /* bits in a word */ \ + BITS_ADDR, /* bits in an address */ \ + 8, /* 8 bits in a byte */ \ + bfd_arch_nios2, \ + NUMBER, \ + "nios2", \ + PRINT, \ + 3, \ + DEFAULT, \ + bfd_default_compatible, \ + bfd_default_scan, \ + bfd_arch_default_fill, \ + NEXT \ + } + +const bfd_arch_info_type bfd_nios2_arch = N (32, 32, 0, "nios2", TRUE, NULL); diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 1fd73cf..9b38317 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -421,6 +421,7 @@ enum elf_target_id MICROBLAZE_ELF_DATA, MIPS_ELF_DATA, MN10300_ELF_DATA, + NIOS2_ELF_DATA, PPC32_ELF_DATA, PPC64_ELF_DATA, S390_ELF_DATA, diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c new file mode 100644 index 0000000..2d6f07a --- /dev/null +++ b/bfd/elf32-nios2.c @@ -0,0 +1,4141 @@ +/* 32-bit ELF support for Nios II. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. */ + +/* This file handles Altera Nios II ELF targets. */ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "elf-bfd.h" +#include "elf/nios2.h" +#include "opcode/nios2.h" + +/* Use RELA relocations. */ +#ifndef USE_RELA +#define USE_RELA +#endif + +#ifdef USE_REL +#undef USE_REL +#endif + +/* Forward declarations. */ +static bfd_reloc_status_type nios2_elf32_ignore_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_hi16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_lo16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_hiadj16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_pcrel_lo16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_pcrel_hiadj16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_pcrel16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_call26_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_gprel_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_ujmp_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_cjmp_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +static bfd_reloc_status_type nios2_elf32_callr_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +/* Target vector. */ +extern const bfd_target bfd_elf32_littlenios2_vec; +extern const bfd_target bfd_elf32_bignios2_vec; + +/* Offset of tp and dtp pointers from start of TLS block. */ +#define TP_OFFSET 0x7000 +#define DTP_OFFSET 0x8000 + +/* The relocation table used for SHT_REL sections. */ +static reloc_howto_type elf_nios2_howto_table_rel[] = { + /* No relocation. */ + HOWTO (R_NIOS2_NONE, /* type */ + 0, /* rightshift */ + 0, /* 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_NIOS2_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* 16-bit signed immediate relocation. */ + HOWTO (R_NIOS2_S16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_signed, /* complain on overflow */ + bfd_elf_generic_reloc, /* special function */ + "R_NIOS2_S16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + FALSE), /* pcrel_offset */ + + /* 16-bit unsigned immediate relocation. */ + HOWTO (R_NIOS2_U16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_unsigned, /* complain on overflow */ + bfd_elf_generic_reloc, /* special function */ + "R_NIOS2_U16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NIOS2_PCREL16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_signed, /* complain on overflow */ + nios2_elf32_pcrel16_relocate, /* special function */ + "R_NIOS2_PCREL16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_NIOS2_CALL26, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_dont, /* complain on overflow */ + nios2_elf32_call26_relocate, /* special function */ + "R_NIOS2_CALL26", /* name */ + FALSE, /* partial_inplace */ + 0xffffffc0, /* src_mask */ + 0xffffffc0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NIOS2_IMM5, + 0, + 2, + 5, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM5", + FALSE, + 0x000007c0, + 0x000007c0, + FALSE), + + HOWTO (R_NIOS2_CACHE_OPX, + 0, + 2, + 5, + FALSE, + 22, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_CACHE_OPX", + FALSE, + 0x07c00000, + 0x07c00000, + FALSE), + + HOWTO (R_NIOS2_IMM6, + 0, + 2, + 6, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM6", + FALSE, + 0x00000fc0, + 0x00000fc0, + FALSE), + + HOWTO (R_NIOS2_IMM8, + 0, + 2, + 8, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM8", + FALSE, + 0x00003fc0, + 0x00003fc0, + FALSE), + + HOWTO (R_NIOS2_HI16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_hi16_relocate, + "R_NIOS2_HI16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_LO16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_lo16_relocate, + "R_NIOS2_LO16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_HIADJ16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_hiadj16_relocate, + "R_NIOS2_HIADJ16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_32, + 0, + 2, /* long */ + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC32", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_16, + 0, + 1, /* short */ + 16, + FALSE, + 0, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC16", + FALSE, + 0x0000ffff, + 0x0000ffff, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_8, + 0, + 0, /* byte */ + 8, + FALSE, + 0, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC8", + FALSE, + 0x000000ff, + 0x000000ff, + FALSE), + + HOWTO (R_NIOS2_GPREL, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_gprel_relocate, + "R_NIOS2_GPREL", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_GNU_VTINHERIT, + 0, + 2, /* short */ + 0, + FALSE, + 0, + complain_overflow_dont, + NULL, + "R_NIOS2_GNU_VTINHERIT", + FALSE, + 0, + 0, + FALSE), + + HOWTO (R_NIOS2_GNU_VTENTRY, + 0, + 2, /* byte */ + 0, + FALSE, + 0, + complain_overflow_dont, + _bfd_elf_rel_vtable_reloc_fn, + "R_NIOS2_GNU_VTENTRY", + FALSE, + 0, + 0, + FALSE), + + HOWTO (R_NIOS2_UJMP, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_ujmp_relocate, + "R_NIOS2_UJMP", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_CJMP, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_cjmp_relocate, + "R_NIOS2_CJMP", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_CALLR, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_callr_relocate, + "R_NIOS2_CALLR", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_ALIGN, + 0, + 2, + 0, + FALSE, + 0, + complain_overflow_dont, + nios2_elf32_ignore_reloc, + "R_NIOS2_ALIGN", + FALSE, + 0, + 0, + TRUE), + + + HOWTO (R_NIOS2_GOT16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_GOT16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_CALL16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_CALL16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_GOTOFF_LO, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_GOTOFF_LO", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_GOTOFF_HA, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_GOTOFF_HA", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_PCREL_LO, + 0, + 2, + 16, + TRUE, + 6, + complain_overflow_dont, + nios2_elf32_pcrel_lo16_relocate, + "R_NIOS2_PCREL_LO", + FALSE, + 0x003fffc0, + 0x003fffc0, + TRUE), + + HOWTO (R_NIOS2_PCREL_HA, + 0, + 2, + 16, + FALSE, /* This is a PC-relative relocation, but we need to subtract + PC ourselves before the HIADJ. */ + 6, + complain_overflow_dont, + nios2_elf32_pcrel_hiadj16_relocate, + "R_NIOS2_PCREL_HA", + FALSE, + 0x003fffc0, + 0x003fffc0, + TRUE), + + HOWTO (R_NIOS2_TLS_GD16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_GD16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_TLS_LDM16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_LDM16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_TLS_LDO16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_LDO16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_TLS_IE16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_IE16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_TLS_LE16, + 0, + 2, + 16, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_LE16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_TLS_DTPMOD, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_DTPMOD", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_TLS_DTPREL, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_DTPREL", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_TLS_TPREL, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_TLS_TPREL", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_COPY, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_COPY", + FALSE, + 0, + 0, + FALSE), + + HOWTO (R_NIOS2_GLOB_DAT, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_GLOB_DAT", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_JUMP_SLOT, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_JUMP_SLOT", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_RELATIVE, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_RELATIVE", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_GOTOFF, + 0, + 2, + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_GOTOFF", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + +/* Add other relocations here. */ +}; + +static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; + +/* Return the howto for relocation RTYPE. */ +static reloc_howto_type * +lookup_howto (unsigned int rtype) +{ + static int initialized = 0; + int i; + int howto_tbl_size = (int) (sizeof (elf_nios2_howto_table_rel) + / sizeof (elf_nios2_howto_table_rel[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[elf_nios2_howto_table_rel[i].type] = i; + } + + BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL); + i = elf_code_to_howto_index[rtype]; + if (i >= howto_tbl_size) + return 0; + return elf_nios2_howto_table_rel + i; +} + +/* Map for converting BFD reloc types to Nios II reloc types. */ +struct elf_reloc_map +{ + bfd_reloc_code_real_type bfd_val; + enum elf_nios2_reloc_type elf_val; +}; + +static const struct elf_reloc_map nios2_reloc_map[] = { + {BFD_RELOC_NIOS2_S16, R_NIOS2_S16}, + {BFD_RELOC_NIOS2_U16, R_NIOS2_U16}, + {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16}, + {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26}, + {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5}, + {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX}, + {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6}, + {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8}, + {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16}, + {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16}, + {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16}, + {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32}, + {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16}, + {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8}, + {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL}, + {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT}, + {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY}, + {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP}, + {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP}, + {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR}, + {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN}, + {BFD_RELOC_NIOS2_GOT16, R_NIOS2_GOT16}, + {BFD_RELOC_NIOS2_CALL16, R_NIOS2_CALL16}, + {BFD_RELOC_NIOS2_GOTOFF_LO, R_NIOS2_GOTOFF_LO}, + {BFD_RELOC_NIOS2_GOTOFF_HA, R_NIOS2_GOTOFF_HA}, + {BFD_RELOC_NIOS2_PCREL_LO, R_NIOS2_PCREL_LO}, + {BFD_RELOC_NIOS2_PCREL_HA, R_NIOS2_PCREL_HA}, + {BFD_RELOC_NIOS2_TLS_GD16, R_NIOS2_TLS_GD16}, + {BFD_RELOC_NIOS2_TLS_LDM16, R_NIOS2_TLS_LDM16}, + {BFD_RELOC_NIOS2_TLS_LDO16, R_NIOS2_TLS_LDO16}, + {BFD_RELOC_NIOS2_TLS_IE16, R_NIOS2_TLS_IE16}, + {BFD_RELOC_NIOS2_TLS_LE16, R_NIOS2_TLS_LE16}, + {BFD_RELOC_NIOS2_TLS_DTPMOD, R_NIOS2_TLS_DTPMOD}, + {BFD_RELOC_NIOS2_TLS_DTPREL, R_NIOS2_TLS_DTPREL}, + {BFD_RELOC_NIOS2_TLS_TPREL, R_NIOS2_TLS_TPREL}, + {BFD_RELOC_NIOS2_COPY, R_NIOS2_COPY}, + {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT}, + {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT}, + {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE}, + {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF} +}; + +/* The Nios II linker needs to keep track of the number of relocs that it + decides to copy as dynamic relocs in check_relocs for each symbol. + This is so that it can later discard them if they are found to be + unnecessary. We store the information in a field extending the + regular ELF linker hash table. */ + +struct elf32_nios2_dyn_relocs +{ + struct elf32_nios2_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + bfd_size_type count; + + /* Number of pc-relative relocs copied for the input section. */ + bfd_size_type pc_count; +}; + +/* Nios II ELF linker hash entry. */ + +struct elf32_nios2_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* Track dynamic relocs copied for this symbol. */ + struct elf32_nios2_dyn_relocs *dyn_relocs; + +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 +#define GOT_TLS_IE 4 + unsigned char tls_type; + + /* We need to detect and take special action for symbols which are only + referenced with %call() and not with %got(). Such symbols do not need + a dynamic GOT reloc in shared objects, only a dynamic PLT reloc. Lazy + linking will not work if the dynamic GOT reloc exists. + To check for this condition efficiently, we compare got_types_used against + CALL16_USED, meaning + (got_types_used & (GOT16_USED | CALL16_USED)) == CALL16_USED. */ +#define GOT16_USED 1 +#define CALL16_USED 2 + unsigned char got_types_used; +}; + +#define elf32_nios2_hash_entry(ent) \ + ((struct elf32_nios2_link_hash_entry *) (ent)) + +/* Get the Nios II elf linker hash table from a link_info structure. */ +#define elf32_nios2_hash_table(info) \ + ((struct elf32_nios2_link_hash_table *) ((info)->hash)) + +/* Nios II ELF linker hash table. */ +struct elf32_nios2_link_hash_table + { + /* The main hash table. */ + struct elf_link_hash_table root; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sdynbss; + asection *srelbss; + asection *sbss; + + union { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ldm_got; + + /* Small local sym cache. */ + struct sym_cache sym_cache; + + bfd_vma res_n_size; + }; + +struct nios2_elf32_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; + + /* TRUE if TLS GD relocs have been seen for this object. */ + bfd_boolean has_tlsgd; +}; + +#define elf32_nios2_tdata(abfd) \ + ((struct nios2_elf32_obj_tdata *) (abfd)->tdata.any) + +#define elf32_nios2_local_got_tls_type(abfd) \ + (elf32_nios2_tdata (abfd)->local_got_tls_type) + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ +#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" + +/* PLT implementation for position-dependent code. */ +static const bfd_vma nios2_plt_entry[] = { /* .PLTn: */ + 0x03c00034, /* movhi r15, %hiadj(plt_got_slot_address) */ + 0x7bc00017, /* ldw r15, %lo(plt_got_slot_address)(r15) */ + 0x7800683a /* jmp r15 */ +}; + +static const bfd_vma nios2_plt0_entry[] = { /* .PLTresolve */ + 0x03800034, /* movhi r14, %hiadj(res_0) */ + 0x73800004, /* addi r14, r14, %lo(res_0) */ + 0x7b9fc83a, /* sub r15, r15, r14 */ + 0x03400034, /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */ + 0x6b800017, /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */ + 0x6b400017, /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */ + 0x6800683a /* jmp r13 */ +}; + +/* PLT implementation for position-independent code. */ +static const bfd_vma nios2_so_plt_entry[] = { /* .PLTn */ + 0x03c00034, /* movhi r15, %hiadj(index * 4) */ + 0x7bc00004, /* addi r15, r15, %lo(index * 4) */ + 0x00000006 /* br .PLTresolve */ +}; + +static const bfd_vma nios2_so_plt0_entry[] = { /* .PLTresolve */ + 0x001ce03a, /* nextpc r14 */ + 0x03400034, /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */ + 0x6b9b883a, /* add r13, r13, r14 */ + 0x6b800017, /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */ + 0x6b400017, /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */ + 0x6800683a /* jmp r13 */ +}; + +/* Implement elf_backend_grok_prstatus: + Support for core dump NOTE sections. */ +static bfd_boolean +nios2_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) +{ + int offset; + size_t size; + + switch (note->descsz) + { + default: + return FALSE; + + case 212: /* Linux/Nios II */ + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 72; + size = 136; + + break; + } + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + size, note->descpos + offset); +} + +/* Implement elf_backend_grok_psinfo. */ +static bfd_boolean +nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) +{ + switch (note->descsz) + { + default: + return FALSE; + + case 124: /* Linux/Nios II elf_prpsinfo */ + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + } + + /* Note that for some reason, a spurious space is tacked + onto the end of the args in some (at least one anyway) + implementations, so strip it off if it exists. */ + + { + char *command = elf_tdata (abfd)->core_command; + int n = strlen (command); + + if (0 < n && command[n - 1] == ' ') + command[n - 1] = '\0'; + } + + return TRUE; +} + +/* Create an entry in a Nios II ELF linker hash table. */ +static struct bfd_hash_entry * +link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, const char *string) +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, + sizeof (struct elf32_nios2_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_elf_link_hash_newfunc (entry, table, string); + if (entry) + { + struct elf32_nios2_link_hash_entry *eh; + + eh = (struct elf32_nios2_link_hash_entry *) entry; + eh->dyn_relocs = NULL; + eh->tls_type = GOT_UNKNOWN; + eh->got_types_used = 0; + } + + return entry; +} + +/* Implement bfd_elf32_bfd_reloc_type_lookup: + Given a BFD reloc type, return a howto structure. */ +static reloc_howto_type * +nios2_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + int i; + for (i = 0; + i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map)); + ++i) + if (nios2_reloc_map[i].bfd_val == code) + return &elf_nios2_howto_table_rel[(int) nios2_reloc_map[i].elf_val]; + return NULL; +} + +/* Implement bfd_elf32_bfd_reloc_name_lookup: + Given a reloc name, return a howto structure. */ +static reloc_howto_type * +nios2_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + for (i = 0; + i < (sizeof (elf_nios2_howto_table_rel) + / sizeof (elf_nios2_howto_table_rel[0])); + i++) + if (elf_nios2_howto_table_rel[i].name + && strcasecmp (elf_nios2_howto_table_rel[i].name, r_name) == 0) + return &elf_nios2_howto_table_rel[i]; + + return NULL; +} + +/* Implement elf_info_to_howto: + Given a ELF32 relocation, fill in a arelent structure. */ +static void +nios2_elf32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + BFD_ASSERT (r_type < R_NIOS2_ILLEGAL); + cache_ptr->howto = &elf_nios2_howto_table_rel[r_type]; +} + +/* Return the base VMA address which should be subtracted from real addresses + when resolving @dtpoff relocation. + This is PT_TLS segment p_vaddr. */ +static bfd_vma +dtpoff_base (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ +static bfd_vma +tpoff (struct bfd_link_info *info, bfd_vma address) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) + return 0; + return address - htab->tls_sec->vma; +} + +/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a + dangerous relocation. */ +static bfd_boolean +nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) +{ + + bfd_boolean gp_found; + struct bfd_hash_entry *h; + struct bfd_link_hash_entry *lh; + + /* If we've already figured out what GP will be, just return it. */ + *pgp = _bfd_get_gp_value (output_bfd); + if (*pgp) + return TRUE; + + h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE); + lh = (struct bfd_link_hash_entry *) h; +lookup: + if (lh) + { + switch (lh->type) + { + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + case bfd_link_hash_common: + gp_found = FALSE; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + gp_found = TRUE; + *pgp = lh->u.def.value; + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + lh = lh->u.i.link; + /* @@FIXME ignoring warning for now */ + goto lookup; + case bfd_link_hash_new: + default: + abort (); + } + } + else + gp_found = FALSE; + + if (!gp_found) + { + /* Only get the error once. */ + *pgp = 4; + _bfd_set_gp_value (output_bfd, *pgp); + return FALSE; + } + + _bfd_set_gp_value (output_bfd, *pgp); + + return TRUE; +} + +/* Retrieve the previously cached _gp pointer, returning bfd_reloc_dangerous + if it's not available as we don't have a link_info pointer available here + to look it up in the output symbol table. We don't need to adjust the + symbol value for an external symbol if we are producing relocatable + output. */ +static bfd_reloc_status_type +nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, + char **error_message, bfd_vma *pgp) +{ + if (bfd_is_und_section (symbol->section) && !relocatable) + { + *pgp = 0; + return bfd_reloc_undefined; + } + + *pgp = _bfd_get_gp_value (output_bfd); + if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)) + { + if (relocatable) + { + /* Make up a value. */ + *pgp = symbol->section->output_section->vma + 0x4000; + _bfd_set_gp_value (output_bfd, *pgp); + } + else + { + *error_message + = (char *) _("global pointer relative relocation when _gp not defined"); + return bfd_reloc_dangerous; + } + } + + return bfd_reloc_ok; +} + +/* The usual way of loading a 32-bit constant into a Nios II register is to + load the high 16 bits in one instruction and then add the low 16 bits with + a signed add. This means that the high halfword needs to be adjusted to + compensate for the sign bit of the low halfword. This function returns the + adjusted high halfword for a given 32-bit constant. */ +static +bfd_vma hiadj (bfd_vma symbol_value) +{ + return ((symbol_value + 0x8000) >> 16) & 0xffff; +} + +/* Do the relocations that require special handling. */ +static bfd_reloc_status_type +nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = (symbol_value >> 16) & 0xffff; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_lo16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = symbol_value & 0xffff; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = hiadj(symbol_value); + return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, + symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_pcrel_lo16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = symbol_value & 0xffff; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_pcrel_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section + ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + symbol_value -= (input_section->output_section->vma + + input_section->output_offset); + symbol_value -= offset; + addend = 0; + symbol_value = hiadj(symbol_value); + return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, + symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_pcrel16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + /* NIOS2 pc relative relocations are relative to the next 32-bit instruction + so we need to subtract 4 before doing a final_link_relocate. */ + symbol_value = symbol_value + addend - 4; + addend = 0; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + /* Check that the relocation is in the same page as the current address. */ + if (((symbol_value + addend) & 0xf0000000) + != ((input_section->output_section->vma + offset) & 0xf0000000)) + return bfd_reloc_overflow; + + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_gprel_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + /* Because we need the output_bfd, the special handling is done + in nios2_elf32_relocate_section or in nios2_elf32_gprel_relocate. */ + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_ujmp_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_do_cjmp_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_do_callr_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, + bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +/* HOWTO handlers for relocations that require special handling. */ + +/* This is for relocations used only when relaxing to ensure + changes in size of section don't screw up .align. */ +static bfd_reloc_status_type +nios2_elf32_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + if (output_bfd != NULL) + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +nios2_elf32_hi16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_hi16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_lo16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_lo16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_hiadj16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_pcrel_lo16_relocate (bfd *abfd, arelent *reloc_entry, + asymbol *symbol, void *data, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_pcrel_lo16_relocate ( + abfd, reloc_entry->howto, input_section, data, reloc_entry->address, + (symbol->value + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_pcrel_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, + asymbol *symbol, void *data, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_pcrel_hiadj16_relocate ( + abfd, reloc_entry->howto, input_section, data, reloc_entry->address, + (symbol->value + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_pcrel16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_pcrel16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_call26_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_call26_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_gprel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, char **msg) +{ + bfd_vma relocation; + bfd_vma gp; + bfd_reloc_status_type r; + + + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + relocation = (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset); + + /* This assumes we've already cached the _gp symbol. */ + r = nios2_elf_final_gp (abfd, symbol, FALSE, msg, &gp); + if (r == bfd_reloc_ok) + { + relocation = relocation + reloc_entry->addend - gp; + reloc_entry->addend = 0; + if ((signed) relocation < -32768 || (signed) relocation > 32767) + { + *msg = _("global pointer relative address out of range"); + r = bfd_reloc_outofrange; + } + else + r = nios2_elf32_do_gprel_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + relocation, reloc_entry->addend); + } + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_ujmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_ujmp_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_cjmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_cjmp_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_callr_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + 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; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_continue; + + return nios2_elf32_do_callr_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + + +/* Implement elf_backend_relocate_section. */ +static bfd_boolean +nios2_elf32_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + struct elf32_nios2_link_hash_table *htab; + asection *sgot; + asection *splt; + asection *sreloc = NULL; + bfd_vma *local_got_offsets; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + + htab = elf32_nios2_hash_table (info); + sgot = htab->root.sgot; + splt = htab->root.splt; + local_got_offsets = elf_local_got_offsets (input_bfd); + + for (rel = relocs; rel < relend; rel++) + { + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + struct elf32_nios2_link_hash_entry *eh; + bfd_vma relocation; + bfd_vma gp; + bfd_vma reloc_address; + bfd_reloc_status_type r = bfd_reloc_ok; + const char *name = NULL; + int r_type; + const char *format; + char msgbuf[256]; + const char* msg = (const char*) NULL; + bfd_boolean unresolved_reloc; + bfd_vma off; + int use_plt; + + r_type = ELF32_R_TYPE (rel->r_info); + r_symndx = ELF32_R_SYM (rel->r_info); + + howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info)); + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { + bfd_boolean warned; + + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned); + } + + if (sec && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + + /* Nothing more to do unless this is a final link. */ + if (info->relocatable) + continue; + + if (sec && sec->output_section) + reloc_address = (sec->output_section->vma + sec->output_offset + + rel->r_offset); + else + reloc_address = 0; + + if (howto) + { + switch (howto->type) + { + case R_NIOS2_HI16: + r = nios2_elf32_do_hi16_relocate (input_bfd, howto, + input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_LO16: + r = nios2_elf32_do_lo16_relocate (input_bfd, howto, + input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_PCREL_LO: + r = nios2_elf32_do_pcrel_lo16_relocate (input_bfd, howto, + input_section, + contents, + rel->r_offset, + relocation, + rel->r_addend); + break; + case R_NIOS2_HIADJ16: + r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_PCREL_HA: + r = nios2_elf32_do_pcrel_hiadj16_relocate (input_bfd, howto, + input_section, + contents, + rel->r_offset, + relocation, + rel->r_addend); + break; + case R_NIOS2_PCREL16: + r = nios2_elf32_do_pcrel16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_GPREL: + /* Turns an absolute address into a gp-relative address. */ + if (!nios2_elf_assign_gp (output_bfd, &gp, info)) + { + format = _("global pointer relative relocation at address " + "0x%08x when _gp not defined\n"); + sprintf (msgbuf, format, reloc_address); + msg = msgbuf; + r = bfd_reloc_dangerous; + } + else + { + bfd_vma symbol_address = rel->r_addend + relocation; + relocation = relocation + rel->r_addend - gp; + rel->r_addend = 0; + if (((signed) relocation < -32768 + || (signed) relocation > 32767) + && (!h + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + format = _("Unable to reach %s (at 0x%08x) from the " + "global pointer (at 0x%08x) because the " + "offset (%d) is out of the allowed range, " + "-32678 to 32767.\n" ); + sprintf (msgbuf, format, name, symbol_address, gp, + (signed)relocation); + msg = msgbuf; + r = bfd_reloc_outofrange; + } + else + r = _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + } + + break; + case R_NIOS2_UJMP: + r = nios2_elf32_do_ujmp_relocate (input_bfd, howto, + input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_CJMP: + r = nios2_elf32_do_cjmp_relocate (input_bfd, howto, + input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_CALLR: + r = nios2_elf32_do_callr_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_CALL26: + /* If we have a call to an undefined weak symbol, we just want + to stuff a zero in the bits of the call instruction and + bypass the normal call26 relocation handling, because it'll + diagnose an overflow error if address 0 isn't in the same + 256MB segment as the call site. Presumably the call + should be guarded by a null check anyway. */ + if (h != NULL && h->root.type == bfd_link_hash_undefweak) + { + BFD_ASSERT (relocation == 0 && rel->r_addend == 0); + r = _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + } + /* Handle relocations which should use the PLT entry. + NIOS2_BFD_RELOC_32 relocations will use the symbol's value, + which may point to a PLT entry, but we don't need to handle + that here. If we created a PLT entry, all branches in this + object should go to it. */ + if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) + { + /* If we've created a .plt section, and assigned a PLT entry + to this function, it should not be known to bind locally. + If it were, we would have cleared the PLT entry. */ + BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h)); + + relocation = (splt->output_section->vma + + splt->output_offset + + h->plt.offset); + + unresolved_reloc = FALSE; + } + r = nios2_elf32_do_call26_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_ALIGN: + r = bfd_reloc_ok; + /* For symmetry this would be + r = nios2_elf32_do_ignore_reloc (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + but do_ignore_reloc would do no more than return + bfd_reloc_ok. */ + break; + + case R_NIOS2_GOT16: + case R_NIOS2_CALL16: + /* Relocation is to the entry for this symbol in the + global offset table. */ + if (sgot == NULL) + { + r = bfd_reloc_notsupported; + break; + } + + use_plt = 0; + + if (h != NULL) + { + bfd_boolean dyn; + + eh = (struct elf32_nios2_link_hash_entry *)h; + use_plt = (eh->got_types_used == CALL16_USED + && h->plt.offset != (bfd_vma) -1); + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) -1); + dyn = elf_hash_table (info)->dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && SYMBOL_REFERENCES_LOCAL (info, h)) + || (ELF_ST_VISIBILITY (h->other) + && h->root.type == bfd_link_hash_undefweak)) + { + /* This is actually a static link, or it is a -Bsymbolic + link and the symbol is defined locally. We must + initialize this entry in the global offset table. + Since the offset must always be a multiple of 4, we + use the least significant bit to record whether we + have initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This is + done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; + } + } + else + unresolved_reloc = FALSE; + } + else + { + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) -1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use the + least significant bit to record whether we have already + generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + bfd_byte *loc; + + srelgot = htab->root.srelgot; + BFD_ASSERT (srelgot != NULL); + + outrel.r_addend = relocation; + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); + loc = srelgot->contents; + loc += (srelgot->reloc_count++ * + sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } + + local_got_offsets[r_symndx] |= 1; + } + } + + if (use_plt && info->shared) + { + off = ((h->plt.offset - 24) / 12 + 3) * 4; + relocation = htab->root.sgotplt->output_offset + off; + } + else + relocation = sgot->output_offset + off; + + /* This relocation does not use the addend. */ + rel->r_addend = 0; + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + + case R_NIOS2_GOTOFF_LO: + case R_NIOS2_GOTOFF_HA: + case R_NIOS2_GOTOFF: + /* Relocation is relative to the start of the + global offset table. */ + + BFD_ASSERT (sgot != NULL); + if (sgot == NULL) + { + r = bfd_reloc_notsupported; + break; + } + + /* Note that sgot->output_offset is not involved in this + calculation. We always want the start of .got. If we + define _GLOBAL_OFFSET_TABLE in a different way, as is + permitted by the ABI, we might have to change this + calculation. */ + relocation -= sgot->output_section->vma; + switch (howto->type) + { + case R_NIOS2_GOTOFF_LO: + r = nios2_elf32_do_lo16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_GOTOFF_HA: + r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, + relocation, + rel->r_addend); + break; + default: + r = _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + } + break; + + case R_NIOS2_TLS_LDO16: + relocation -= dtpoff_base (info) + DTP_OFFSET; + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_TLS_LDM16: + if (htab->root.sgot == NULL) + abort (); + + off = htab->tls_ldm_got.offset; + + if ((off & 1) != 0) + off &= ~1; + else + { + /* If we don't know the module number, create a relocation + for it. */ + if (info->shared) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + if (htab->root.srelgot == NULL) + abort (); + + outrel.r_addend = 0; + outrel.r_offset = (htab->root.sgot->output_section->vma + + htab->root.sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_NIOS2_TLS_DTPMOD); + + loc = htab->root.srelgot->contents; + loc += (htab->root.srelgot->reloc_count++ + * sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } + else + bfd_put_32 (output_bfd, 1, + htab->root.sgot->contents + off); + + htab->tls_ldm_got.offset |= 1; + } + + relocation = (htab->root.sgot->output_offset + off); + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + + break; + case R_NIOS2_TLS_GD16: + case R_NIOS2_TLS_IE16: + { + int indx; + char tls_type; + + if (htab->root.sgot == NULL) + abort (); + + indx = 0; + if (h != NULL) + { + bfd_boolean dyn; + dyn = htab->root.dynamic_sections_created; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + && (!info->shared + || !SYMBOL_REFERENCES_LOCAL (info, h))) + { + unresolved_reloc = FALSE; + indx = h->dynindx; + } + off = h->got.offset; + tls_type = (((struct elf32_nios2_link_hash_entry *) h) + ->tls_type); + } + else + { + if (local_got_offsets == NULL) + abort (); + off = local_got_offsets[r_symndx]; + tls_type = (elf32_nios2_local_got_tls_type (input_bfd) + [r_symndx]); + } + + if (tls_type == GOT_UNKNOWN) + abort (); + + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_boolean need_relocs = FALSE; + Elf_Internal_Rela outrel; + bfd_byte *loc = NULL; + int cur_off = off; + + /* The GOT entries have not been initialized yet. Do it + now, and emit any relocations. If both an IE GOT and a + GD GOT are necessary, we emit the GD first. */ + + if ((info->shared || indx != 0) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + need_relocs = TRUE; + if (htab->root.srelgot == NULL) + abort (); + loc = htab->root.srelgot->contents; + loc += (htab->root.srelgot->reloc_count * + sizeof (Elf32_External_Rela)); + } + + if (tls_type & GOT_TLS_GD) + { + if (need_relocs) + { + outrel.r_addend = 0; + outrel.r_offset = (htab->root.sgot->output_section->vma + + htab->root.sgot->output_offset + + cur_off); + outrel.r_info = ELF32_R_INFO (indx, + R_NIOS2_TLS_DTPMOD); + + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + loc); + htab->root.srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rela); + + if (indx == 0) + bfd_put_32 (output_bfd, + (relocation - dtpoff_base (info) - + DTP_OFFSET), + htab->root.sgot->contents + cur_off + 4); + else + { + outrel.r_addend = 0; + outrel.r_info = ELF32_R_INFO (indx, + R_NIOS2_TLS_DTPREL); + outrel.r_offset += 4; + + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + loc); + htab->root.srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rela); + } + } + else + { + /* If we are not emitting relocations for a + general dynamic reference, then we must be in a + static link or an executable link with the + symbol binding locally. Mark it as belonging + to module 1, the executable. */ + bfd_put_32 (output_bfd, 1, + htab->root.sgot->contents + cur_off); + bfd_put_32 (output_bfd, (relocation - + dtpoff_base (info) - + DTP_OFFSET), + htab->root.sgot->contents + cur_off + 4); + } + + cur_off += 8; + } + + if (tls_type & GOT_TLS_IE) + { + if (need_relocs) + { + if (indx == 0) + outrel.r_addend = (relocation - + dtpoff_base (info)); + else + outrel.r_addend = 0; + outrel.r_offset = (htab->root.sgot->output_section->vma + + htab->root.sgot->output_offset + + cur_off); + outrel.r_info = ELF32_R_INFO (indx, + R_NIOS2_TLS_TPREL); + + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + loc); + htab->root.srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rela); + } + else + bfd_put_32 (output_bfd, (tpoff (info, relocation) + - TP_OFFSET), + htab->root.sgot->contents + cur_off); + cur_off += 4; + } + + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + } + + if ((tls_type & GOT_TLS_GD) && r_type != R_NIOS2_TLS_GD16) + off += 8; + relocation = (htab->root.sgot->output_offset + off); + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + } + + break; + case R_NIOS2_TLS_LE16: + if (info->shared && !info->pie) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): R_NIOS2_TLS_LE16 relocation not " + "permitted in shared object"), + input_bfd, input_section, + (long) rel->r_offset, howto->name); + return FALSE; + } + else + relocation = tpoff (info, relocation) - TP_OFFSET; + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + + case R_NIOS2_BFD_RELOC_32: + if (info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, relocate; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + skip = FALSE; + relocate = FALSE; + + outrel.r_offset + = _bfd_elf_section_offset (output_bfd, info, + input_section, rel->r_offset); + if (outrel.r_offset == (bfd_vma) -1) + skip = TRUE; + else if (outrel.r_offset == (bfd_vma) -2) + skip = TRUE, relocate = TRUE; + outrel.r_offset += (input_section->output_section->vma + + input_section->output_offset); + + if (skip) + memset (&outrel, 0, sizeof outrel); + else if (h != NULL + && h->dynindx != -1 + && (!info->shared + || !info->symbolic + || !h->def_regular)) + { + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + else + { + /* This symbol is local, or marked to become local. */ + outrel.r_addend = relocation + rel->r_addend; + relocate = TRUE; + outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); + } + + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + + /* This reloc will be computed at runtime, so there's no + need to do anything now, except for R_NIOS2_BFD_RELOC_32 + relocations that have been turned into + R_NIOS2_RELATIVE. */ + if (!relocate) + break; + } + + r = _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + + case R_NIOS2_TLS_DTPREL: + relocation -= dtpoff_base (info); + /* Fall through. */ + + default: + r = _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + } + } + else + r = bfd_reloc_notsupported; + + if (r != bfd_reloc_ok) + { + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL || *name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow (info, NULL, name, + howto->name, (bfd_vma) 0, + input_bfd, input_section, + rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol (info, name, input_bfd, + input_section, + rel->r_offset, TRUE); + break; + + case bfd_reloc_outofrange: + if (msg == NULL) + msg = _("relocation out of range"); + break; + + case bfd_reloc_notsupported: + if (msg == NULL) + msg = _("unsupported relocation"); + break; + + case bfd_reloc_dangerous: + if (msg == NULL) + msg = _("dangerous relocation"); + break; + + default: + if (msg == NULL) + msg = _("unknown error"); + break; + } + + if (msg) + { + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return FALSE; + } + } + } + return TRUE; +} + +/* Implement elf-backend_section_flags: + Convert NIOS2 specific section flags to bfd internal section flags. */ +static bfd_boolean +nios2_elf32_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr) +{ + if (hdr->sh_flags & SHF_NIOS2_GPREL) + *flags |= SEC_SMALL_DATA; + + return TRUE; +} + +/* Implement elf_backend_fake_sections: + Set the correct type for an NIOS2 ELF section. We do this by the + section name, which is a hack, but ought to work. */ +static bfd_boolean +nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, + Elf_Internal_Shdr *hdr, asection *sec) +{ + register const char *name = bfd_get_section_name (abfd, sec); + + if ((sec->flags & SEC_SMALL_DATA) + || strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0 + || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) + hdr->sh_flags |= SHF_NIOS2_GPREL; + + return TRUE; +} + +/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ +static bfd_boolean +create_got_section (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + + if (! _bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + /* In order for the two loads in .PLTresolve to share the same %hiadj, + _GLOBAL_OFFSET_TABLE_ must be aligned to a 16-byte boundary. */ + if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt, 4)) + return FALSE; + + return TRUE; +} + +/* Implement elf_backend_create_dynamic_sections: + Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and + .rela.bss sections in DYNOBJ, and set up shortcuts to them in our + hash table. */ +static bfd_boolean +nios2_elf32_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + if (!htab->root.sgot && !create_got_section (dynobj, info)) + return FALSE; + + _bfd_elf_create_dynamic_sections (dynobj, info); + + /* In order for the two loads in a shared object .PLTresolve to share the + same %hiadj, the start of the PLT (as well as the GOT) must be aligned + to a 16-byte boundary. This is because the addresses for these loads + include the -(.plt+4) PIC correction. */ + if (!bfd_set_section_alignment (dynobj, htab->root.splt, 4)) + return FALSE; + + htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); + if (!htab->sdynbss) + return FALSE; + if (!info->shared) + { + htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); + if (!htab->srelbss) + return FALSE; + } + + return TRUE; +} + +/* Implement elf_backend_copy_indirect_symbol: + Copy the extra info we tack onto an elf_link_hash_entry. */ +static void +nios2_elf32_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf32_nios2_link_hash_entry *edir, *eind; + + edir = (struct elf32_nios2_link_hash_entry *) dir; + eind = (struct elf32_nios2_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf32_nios2_dyn_relocs **pp; + struct elf32_nios2_dyn_relocs *p; + + /* Add reloc counts against the indirect sym to the direct sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) + { + struct elf32_nios2_dyn_relocs *q; + + for (q = edir->dyn_relocs; q != NULL; q = q->next) + if (q->sec == p->sec) + { + q->pc_count += p->pc_count; + q->count += p->count; + *pp = p->next; + break; + } + if (q == NULL) + pp = &p->next; + } + *pp = edir->dyn_relocs; + } + + edir->dyn_relocs = eind->dyn_relocs; + eind->dyn_relocs = NULL; + } + + if (ind->root.type == bfd_link_hash_indirect + && dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + + edir->got_types_used |= eind->got_types_used; + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +/* Implement elf_backend_check_relocs: + Look through the relocs for a section during the first phase. */ +static bfd_boolean +nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, const Elf_Internal_Rela *relocs) +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + struct elf32_nios2_link_hash_table *htab; + asection *sgot; + asection *srelgot; + asection *sreloc = NULL; + bfd_signed_vma *local_got_refcounts; + + if (info->relocatable) + return TRUE; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = (sym_hashes + + symtab_hdr->sh_size / sizeof (Elf32_External_Sym)); + if (!elf_bad_symtab (abfd)) + sym_hashes_end -= symtab_hdr->sh_info; + local_got_refcounts = elf_local_got_refcounts (abfd); + + htab = elf32_nios2_hash_table (info); + sgot = htab->root.sgot; + srelgot = htab->root.srelgot; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned int r_type; + struct elf_link_hash_entry *h; + unsigned long r_symndx; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + } + + r_type = ELF32_R_TYPE (rel->r_info); + + switch (r_type) + { + case R_NIOS2_GOT16: + case R_NIOS2_CALL16: + case R_NIOS2_TLS_GD16: + case R_NIOS2_TLS_IE16: + /* This symbol requires a global offset table entry. */ + { + int tls_type, old_tls_type; + + switch (r_type) + { + default: + case R_NIOS2_GOT16: + case R_NIOS2_CALL16: + tls_type = GOT_NORMAL; + break; + case R_NIOS2_TLS_GD16: + tls_type = GOT_TLS_GD; + break; + case R_NIOS2_TLS_IE16: + tls_type = GOT_TLS_IE; + break; + } + + if (dynobj == NULL) + { + /* Create the .got section. */ + elf_hash_table (info)->dynobj = dynobj = abfd; + nios2_elf32_create_dynamic_sections (dynobj, info); + } + + if (sgot == NULL) + { + sgot = htab->root.sgot; + BFD_ASSERT (sgot != NULL); + } + + if (srelgot == NULL + && (h != NULL || info->shared)) + { + srelgot = htab->root.srelgot; + BFD_ASSERT (srelgot != NULL); + } + + if (h != NULL) + { + struct elf32_nios2_link_hash_entry *eh + = (struct elf32_nios2_link_hash_entry *)h; + h->got.refcount++; + old_tls_type = elf32_nios2_hash_entry(h)->tls_type; + if (r_type == R_NIOS2_CALL16) + { + /* Make sure a plt entry is created for this symbol if + it turns out to be a function defined by a dynamic + object. */ + h->plt.refcount++; + h->needs_plt = 1; + h->type = STT_FUNC; + eh->got_types_used |= CALL16_USED; + } + else + eh->got_types_used |= GOT16_USED; + } + else + { + /* This is a global offset table entry for a local symbol. */ + if (local_got_refcounts == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + size *= (sizeof (bfd_signed_vma) + sizeof (char)); + local_got_refcounts + = ((bfd_signed_vma *) bfd_zalloc (abfd, size)); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + elf32_nios2_local_got_tls_type (abfd) + = (char *) (local_got_refcounts + symtab_hdr->sh_info); + } + local_got_refcounts[r_symndx]++; + old_tls_type = elf32_nios2_local_got_tls_type (abfd) [r_symndx]; + } + + /* We will already have issued an error message if there is a + TLS / non-TLS mismatch, based on the symbol type. We don't + support any linker relaxations. So just combine any TLS + types needed. */ + if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL + && tls_type != GOT_NORMAL) + tls_type |= old_tls_type; + + if (old_tls_type != tls_type) + { + if (h != NULL) + elf32_nios2_hash_entry (h)->tls_type = tls_type; + else + elf32_nios2_local_got_tls_type (abfd) [r_symndx] = tls_type; + } + } + /* Fall through */ + case R_NIOS2_TLS_LDM16: + if (r_type == R_NIOS2_TLS_LDM16) + htab->tls_ldm_got.refcount++; + + if (htab->root.sgot == NULL) + { + if (htab->root.dynobj == NULL) + htab->root.dynobj = abfd; + if (!create_got_section (htab->root.dynobj, info)) + return FALSE; + } + break; + + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_NIOS2_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_NIOS2_GNU_VTENTRY: + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + + case R_NIOS2_BFD_RELOC_32: + case R_NIOS2_CALL26: + case R_NIOS2_HIADJ16: + case R_NIOS2_LO16: + + if (h != NULL) + { + /* If this reloc is in a read-only section, we might + need a copy reloc. We can't check reliably at this + stage whether the section is read-only, as input + sections have not yet been mapped to output sections. + Tentatively set the flag for now, and correct in + adjust_dynamic_symbol. */ + if (!info->shared) + h->non_got_ref = 1; + + /* Make sure a plt entry is created for this symbol if it + turns out to be a function defined by a dynamic object. */ + h->plt.refcount++; + + if (r_type == R_NIOS2_CALL26) + h->needs_plt = 1; + } + + /* If we are creating a shared library, we need to copy the + reloc into the shared library. */ + if (info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (r_type == R_NIOS2_BFD_RELOC_32 + || (h != NULL && ! h->needs_plt + && (! info->symbolic || ! h->def_regular)))) + { + struct elf32_nios2_dyn_relocs *p; + struct elf32_nios2_dyn_relocs **head; + + /* When creating a shared object, we must copy these + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ + if (sreloc == NULL) + { + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, dynobj, 2, abfd, TRUE); + if (sreloc == NULL) + return FALSE; + } + + /* If this is a global symbol, we count the number of + relocations we need for this symbol. */ + if (h != NULL) + head = &((struct elf32_nios2_link_hash_entry *) h)->dyn_relocs; + else + { + /* Track dynamic relocs needed for local syms too. + We really need local syms available to do this + easily. Oh well. */ + + asection *s; + void *vpp; + Elf_Internal_Sym *isym; + + 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 elf32_nios2_dyn_relocs **) vpp; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + p = ((struct elf32_nios2_dyn_relocs *) + bfd_alloc (htab->root.dynobj, amt)); + if (p == NULL) + return FALSE; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + + p->count += 1; + + } + break; + } + } + + return TRUE; +} + + +/* Implement elf_backend_gc_mark_hook: + Return the section that should be marked against GC for a given + relocation. */ +static asection * +nios2_elf32_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + if (h != NULL) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_NIOS2_GNU_VTINHERIT: + case R_NIOS2_GNU_VTENTRY: + return NULL; + } + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} + +/* Implement elf_backend_gc_sweep_hook: + Update the got entry reference counts for the section being removed. */ +static bfd_boolean +nios2_elf32_gc_sweep_hook (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel, *relend; + bfd *dynobj; + + if (info->relocatable) + return TRUE; + + elf_section_data (sec)->local_dynrel = NULL; + + dynobj = elf_hash_table (info)->dynobj; + if (dynobj == NULL) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h = NULL; + int r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + r_type = ELF32_R_TYPE (rel->r_info); + switch (r_type) + { + case R_NIOS2_GOT16: + case R_NIOS2_CALL16: + if (h != NULL) + { + if (h->got.refcount > 0) + --h->got.refcount; + } + else if (local_got_refcounts != NULL) + { + if (local_got_refcounts[r_symndx] > 0) + --local_got_refcounts[r_symndx]; + } + break; + + case R_NIOS2_PCREL_LO: + case R_NIOS2_PCREL_HA: + case R_NIOS2_BFD_RELOC_32: + case R_NIOS2_CALL26: + if (h != NULL) + { + struct elf32_nios2_link_hash_entry *eh; + struct elf32_nios2_dyn_relocs **pp; + struct elf32_nios2_dyn_relocs *p; + + eh = (struct elf32_nios2_link_hash_entry *) h; + + if (h->plt.refcount > 0) + --h->plt.refcount; + + if (r_type == R_NIOS2_PCREL_LO || r_type == R_NIOS2_PCREL_HA + || r_type == R_NIOS2_BFD_RELOC_32) + { + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; + pp = &p->next) + if (p->sec == sec) + { + p->count -= 1; + if (p->count == 0) + *pp = p->next; + break; + } + } + } + break; + + default: + break; + } + } + + return TRUE; +} + +/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC. */ +static void +nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value) +{ + bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset); + + BFD_ASSERT(value <= 0xffff); + + bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6), + sec->contents + offset); +} + +/* Install COUNT 32-bit values DATA starting at offset OFFSET into + section SEC. */ +static void +nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset, + int count) +{ + while (count--) + { + bfd_put_32 (sec->owner, *data, sec->contents + offset); + offset += 4; + ++data; + } +} + +/* Implement elf_backend_finish_dynamic_symbols: + Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ +static bfd_boolean +nios2_elf32_finish_dynamic_symbol (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + struct elf32_nios2_link_hash_table *htab; + struct elf32_nios2_link_hash_entry *eh + = (struct elf32_nios2_link_hash_entry *)h; + int use_plt; + + htab = elf32_nios2_hash_table (info); + + if (h->plt.offset != (bfd_vma) -1) + { + asection *splt; + asection *sgotplt; + asection *srela; + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rela rela; + bfd_byte *loc; + bfd_vma got_address; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + BFD_ASSERT (h->dynindx != -1); + splt = htab->root.splt; + sgotplt = htab->root.sgotplt; + srela = htab->root.srelplt; + BFD_ASSERT (splt != NULL && sgotplt != NULL && srela != NULL); + + /* Emit the PLT entry. */ + if (info->shared) + { + nios2_elf32_install_data (splt, nios2_so_plt_entry, h->plt.offset, + 3); + plt_index = (h->plt.offset - 24) / 12; + got_offset = (plt_index + 3) * 4; + nios2_elf32_install_imm16 (splt, h->plt.offset, + hiadj(plt_index * 4)); + nios2_elf32_install_imm16 (splt, h->plt.offset + 4, + (plt_index * 4) & 0xffff); + nios2_elf32_install_imm16 (splt, h->plt.offset + 8, + 0xfff4 - h->plt.offset); + got_address = (sgotplt->output_section->vma + sgotplt->output_offset + + got_offset); + + /* Fill in the entry in the global offset table. There are no + res_n slots for a shared object PLT, instead the .got.plt entries + point to the PLT entries. */ + bfd_put_32 (output_bfd, + splt->output_section->vma + splt->output_offset + + h->plt.offset, sgotplt->contents + got_offset); + } + else + { + plt_index = (h->plt.offset - 28 - htab->res_n_size) / 12; + got_offset = (plt_index + 3) * 4; + + nios2_elf32_install_data (splt, nios2_plt_entry, h->plt.offset, 3); + got_address = (sgotplt->output_section->vma + sgotplt->output_offset + + got_offset); + nios2_elf32_install_imm16 (splt, h->plt.offset, hiadj(got_address)); + nios2_elf32_install_imm16 (splt, h->plt.offset + 4, + got_address & 0xffff); + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + splt->output_section->vma + splt->output_offset + + plt_index * 4, sgotplt->contents + got_offset); + } + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = got_address; + rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_JUMP_SLOT); + rela.r_addend = 0; + loc = srela->contents + plt_index * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + /* If the symbol is weak, we do need to clear the value. + Otherwise, the PLT entry would provide a definition for + the symbol even if the symbol wasn't defined anywhere, + and so the symbol would never be NULL. */ + if (!h->ref_regular_nonweak) + sym->st_value = 0; + } + } + + use_plt = (eh->got_types_used == CALL16_USED + && h->plt.offset != (bfd_vma) -1); + + if (!use_plt && h->got.offset != (bfd_vma) -1 + && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_GD) == 0 + && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_IE) == 0) + { + asection *sgot; + asection *srela; + Elf_Internal_Rela rela; + bfd_byte *loc; + bfd_vma offset; + + /* This symbol has an entry in the global offset table. Set it + up. */ + sgot = htab->root.sgot; + srela = htab->root.srelgot; + BFD_ASSERT (sgot != NULL && srela != NULL); + + offset = (h->got.offset & ~(bfd_vma) 1); + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + offset); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. Likewise if + the symbol was forced to be local because of a version file. + The entry in the global offset table will already have been + initialized in the relocate_section function. */ + + if (info->shared && SYMBOL_REFERENCES_LOCAL (info, h)) + { + rela.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); + rela.r_addend = bfd_get_signed_32 (output_bfd, + (sgot->contents + offset)); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset); + } + else + { + bfd_put_32 (output_bfd, (bfd_vma) 0, + sgot->contents + offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_GLOB_DAT); + rela.r_addend = 0; + } + + loc = srela->contents; + loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + } + + if (use_plt && h->got.offset != (bfd_vma) -1) + { + bfd_vma offset = (h->got.offset & ~(bfd_vma) 1); + asection *sgot = htab->root.sgot; + asection *splt = htab->root.splt; + bfd_put_32 (output_bfd, (splt->output_section->vma + splt->output_offset + + h->plt.offset), + sgot->contents + offset); + } + + if (h->needs_copy) + { + asection *s; + Elf_Internal_Rela rela; + bfd_byte *loc; + + /* This symbol needs a copy reloc. Set it up. */ + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = htab->srelbss; + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_COPY); + rela.r_addend = 0; + loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || h == elf_hash_table (info)->hgot) + sym->st_shndx = SHN_ABS; + + return TRUE; +} + +/* Implement elf_backend_finish_dynamic_sections. */ +static bfd_boolean +nios2_elf32_finish_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + bfd *dynobj; + asection *sgotplt; + asection *sdyn; + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + dynobj = elf_hash_table (info)->dynobj; + sgotplt = htab->root.sgotplt; + BFD_ASSERT (sgotplt != NULL); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = htab->root.splt; + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_PLTGOT: + s = htab->root.sgot; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->output_section->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_JMPREL: + s = htab->root.srelplt; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->output_section->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTRELSZ: + s = htab->root.srelplt; + BFD_ASSERT (s != NULL); + dyn.d_un.d_val = s->size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_RELASZ: + /* The procedure linkage table relocs (DT_JMPREL) should + not be included in the overall relocs (DT_RELA). + Therefore, we override the DT_RELASZ entry here to + make it not include the JMPREL relocs. Since the + linker script arranges for .rela.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_RELA entry. */ + s = htab->root.srelplt; + if (s != NULL) + dyn.d_un.d_val -= s->size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_NIOS2_GP: + s = htab->root.sgot; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->output_section->vma + 0x7ff0; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } + } + + /* Fill in the first entry in the procedure linkage table. */ + if (splt->size > 0) + { + bfd_vma got_address = (sgotplt->output_section->vma + + sgotplt->output_offset); + if (info->shared) + { + bfd_vma corrected = got_address - (splt->output_section->vma + + splt->output_offset + 4); + nios2_elf32_install_data (splt, nios2_so_plt0_entry, 0, 6); + nios2_elf32_install_imm16 (splt, 4, hiadj (corrected)); + nios2_elf32_install_imm16 (splt, 12, (corrected & 0xffff) + 4); + nios2_elf32_install_imm16 (splt, 16, (corrected & 0xffff) + 8); + + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = 24; + } + else + { + /* Divide by 4 here, not 3 because we already corrected for the + res_N branches. */ + bfd_vma res_size = (splt->size - 28) / 4; + bfd_vma res_start = (splt->output_section->vma + + splt->output_offset); + bfd_vma res_offset; + + for (res_offset = 0; res_offset < res_size; res_offset += 4) + bfd_put_32 (output_bfd, + 6 | ((res_size - (res_offset + 4)) << 6), + splt->contents + res_offset); + + nios2_elf32_install_data (splt, nios2_plt0_entry, res_size, 7); + nios2_elf32_install_imm16 (splt, res_size, hiadj (res_start)); + nios2_elf32_install_imm16 (splt, res_size + 4, + res_start & 0xffff); + nios2_elf32_install_imm16 (splt, res_size + 12, + hiadj (got_address)); + nios2_elf32_install_imm16 (splt, res_size + 16, + (got_address & 0xffff) + 4); + nios2_elf32_install_imm16 (splt, res_size + 20, + (got_address & 0xffff) + 8); + + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = 28 + res_size; + } + } + } + /* Fill in the first three entries in the global offset table. */ + if (sgotplt->size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgotplt->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8); + } + + elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4; + + return TRUE; +} + +/* Implement elf_backend_adjust_dynamic_symbol: + Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ +static bfd_boolean +nios2_elf32_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf32_nios2_link_hash_table *htab; + bfd *dynobj; + asection *s; + unsigned align2; + + htab = elf32_nios2_hash_table (info); + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && (h->needs_plt + || h->u.weakdef != NULL + || (h->def_dynamic + && h->ref_regular + && !h->def_regular))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC || h->needs_plt) + { + if (h->plt.refcount <= 0 + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) + { + /* This case can occur if we saw a PLT reloc in an input + file, but the symbol was never referred to by a dynamic + object, or if all references were garbage collected. In + such a case, we don't actually need to build a procedure + linkage table, and we can just do a PCREL reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + return TRUE; + } + + /* Reinitialize the plt offset now that it is not used as a reference + count any more. */ + h->plt.offset = (bfd_vma) -1; + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + return TRUE; + } + + /* If there are no non-GOT references, we do not need a copy + relocation. */ + if (!h->non_got_ref) + return TRUE; + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. + If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + return TRUE; + + if (h->size == 0) + { + (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), + h->root.root.string); + return TRUE; + } + + /* We must allocate the symbol in our .dynbss section, which will + become part of the .bss section of the executable. There will be + an entry for this symbol in the .dynsym section. The dynamic + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + s = htab->sdynbss; + BFD_ASSERT (s != NULL); + + /* We must generate a R_NIOS2_COPY reloc to tell the dynamic linker to + copy the initial value out of the dynamic object and into the + runtime process image. We need to remember the offset into the + .rela.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + { + asection *srel; + + srel = htab->srelbss; + BFD_ASSERT (srel != NULL); + srel->size += sizeof (Elf32_External_Rela); + h->needs_copy = 1; + } + + align2 = bfd_log2 (h->size); + if (align2 > h->root.u.def.section->alignment_power) + align2 = h->root.u.def.section->alignment_power; + + /* Align dynbss. */ + s->size = BFD_ALIGN (s->size, (bfd_size_type)1 << align2); + if (align2 > bfd_get_section_alignment (dynobj, s) + && !bfd_set_section_alignment (dynobj, s, align2)) + return FALSE; + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->size; + + /* Increment the section size to make room for the symbol. */ + s->size += h->size; + + return TRUE; +} + +/* Worker function for nios2_elf32_size_dynamic_sections. */ +static bfd_boolean +adjust_dynrelocs (struct elf_link_hash_entry *h, PTR inf) +{ + struct bfd_link_info *info; + struct elf32_nios2_link_hash_table *htab; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + /* When warning symbols are created, they **replace** the "real" + entry in the hash table, thus we never get to see the real + symbol in a hash traversal. So look at it now. */ + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + info = (struct bfd_link_info *) inf; + htab = elf32_nios2_hash_table (info); + + if (h->plt.offset != (bfd_vma)-1) + h->plt.offset += htab->res_n_size; + if (htab->root.splt == h->root.u.def.section) + h->root.u.def.value += htab->res_n_size; + + return TRUE; +} + +/* Another worker function for nios2_elf32_size_dynamic_sections. + Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) +{ + struct bfd_link_info *info; + struct elf32_nios2_link_hash_table *htab; + struct elf32_nios2_link_hash_entry *eh; + struct elf32_nios2_dyn_relocs *p; + int use_plt; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + /* When warning symbols are created, they **replace** the "real" + entry in the hash table, thus we never get to see the real + symbol in a hash traversal. So look at it now. */ + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + info = (struct bfd_link_info *) inf; + htab = elf32_nios2_hash_table (info); + + if (htab->root.dynamic_sections_created + && h->plt.refcount > 0) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) + { + asection *s = htab->root.splt; + + /* Allocate room for the header. */ + if (s->size == 0) + { + if (info->shared) + s->size = 24; + else + s->size = 28; + } + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += 12; + + /* We also need to make an entry in the .rela.plt section. */ + htab->root.srelplt->size += sizeof (Elf32_External_Rela); + + /* And the .got.plt section. */ + htab->root.sgotplt->size += 4; + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + eh = (struct elf32_nios2_link_hash_entry *) h; + use_plt = (eh->got_types_used == CALL16_USED + && h->plt.offset != (bfd_vma) -1); + + if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + int tls_type = eh->tls_type; + int indx; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + s = htab->root.sgot; + h->got.offset = s->size; + + if (tls_type == GOT_UNKNOWN) + abort (); + + if (tls_type == GOT_NORMAL) + /* Non-TLS symbols need one GOT slot. */ + s->size += 4; + else + { + if (tls_type & GOT_TLS_GD) + /* R_NIOS2_TLS_GD16 needs 2 consecutive GOT slots. */ + s->size += 8; + if (tls_type & GOT_TLS_IE) + /* R_NIOS2_TLS_IE16 needs one GOT slot. */ + s->size += 4; + } + + dyn = htab->root.dynamic_sections_created; + + indx = 0; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + && (!info->shared + || !SYMBOL_REFERENCES_LOCAL (info, h))) + indx = h->dynindx; + + if (tls_type != GOT_NORMAL + && (info->shared || indx != 0) + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + if (tls_type & GOT_TLS_IE) + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + + if (tls_type & GOT_TLS_GD) + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + + if ((tls_type & GOT_TLS_GD) && indx != 0) + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + } + else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && !use_plt + && (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + } + else + h->got.offset = (bfd_vma) -1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (info->shared) + { + if (h->def_regular + && (h->forced_local || info->symbolic)) + { + struct elf32_nios2_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + } + else + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + if (!h->non_got_ref + && ((h->def_dynamic && !h->def_regular) + || (htab->root.dynamic_sections_created + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rela); + } + + return TRUE; +} + +/* Implement elf_backend_size_dynamic_sections: + Set the sizes of the dynamic sections. */ +static bfd_boolean +nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + bfd *dynobj; + asection *s; + bfd_boolean plt; + bfd_boolean got; + bfd_boolean relocs; + bfd *ibfd; + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + htab->res_n_size = 0; + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (info->executable) + { + s = bfd_get_linker_section (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + else + { + /* We may have created entries in the .rela.got section. + However, if we are not creating the dynamic sections, we will + not actually use these entries. Reset the size of .rela.got, + which will cause it to get stripped from the output file + below. */ + s = htab->root.srelgot; + if (s != NULL) + s->size = 0; + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + char *local_tls_type; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + asection *srel; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + continue; + + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf32_nios2_dyn_relocs *p; + + for (p = 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)) + { + /* Input section has been discarded, either because + it is a copy of a linkonce section or due to + linker script /DISCARD/, so we'll be discarding + the relocs too. */ + } + else if (p->count != 0) + { + srel = elf_section_data (p->sec)->sreloc; + srel->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) + continue; + + symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + end_local_got = local_got + locsymcount; + local_tls_type = elf32_nios2_local_got_tls_type (ibfd); + s = htab->root.sgot; + srel = htab->root.srelgot; + for (; local_got < end_local_got; ++local_got, ++local_tls_type) + { + if (*local_got > 0) + { + *local_got = s->size; + if (*local_tls_type & GOT_TLS_GD) + /* TLS_GD relocs need an 8-byte structure in the GOT. */ + s->size += 8; + if (*local_tls_type & GOT_TLS_IE) + s->size += 4; + if (*local_tls_type == GOT_NORMAL) + s->size += 4; + + if (info->shared || *local_tls_type == GOT_TLS_GD) + srel->size += sizeof (Elf32_External_Rela); + } + else + *local_got = (bfd_vma) -1; + } + } + + if (htab->tls_ldm_got.refcount > 0) + { + /* Allocate two GOT entries and one dynamic relocation (if necessary) + for R_NIOS2_TLS_LDM16 relocations. */ + htab->tls_ldm_got.offset = htab->root.sgot->size; + htab->root.sgot->size += 8; + if (info->shared) + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + } + else + htab->tls_ldm_got.offset = -1; + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info); + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + plt = FALSE; + got = FALSE; + relocs = FALSE; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + if (strcmp (name, ".plt") == 0) + { + /* Remember whether there is a PLT. */ + plt = s->size != 0; + + /* Correct for the number of res_N branches. */ + if (plt && !info->shared) + { + htab->res_n_size = (s->size-28) / 3; + s->size += htab->res_n_size; + } + } + else if (CONST_STRNEQ (name, ".rela")) + { + if (s->size != 0) + { + relocs = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else if (CONST_STRNEQ (name, ".got")) + got = s->size != 0; + else if (strcmp (name, ".dynbss") != 0) + /* It's not one of our sections, so don't allocate space. */ + continue; + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + s->flags |= SEC_EXCLUDE; + continue; + } + + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + /* Allocate memory for the section contents. */ + /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. + Unused entries should be reclaimed before the section's contents + are written out, but at the moment this does not happen. Thus in + order to prevent writing out garbage, we initialize the section's + contents to zero. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); + if (s->contents == NULL) + return FALSE; + } + + /* Adjust dynamic symbols that point to the plt to account for the + now-known number of resN slots. */ + if (htab->res_n_size) + elf_link_hash_traverse (& htab->root, adjust_dynrelocs, info); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_nios2_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ +#define add_dynamic_entry(TAG, VAL) \ + _bfd_elf_add_dynamic_entry (info, TAG, VAL) + + if (!info->shared && !add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + + if (got && !add_dynamic_entry (DT_PLTGOT, 0)) + return FALSE; + + if (plt + && (!add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_RELA) + || !add_dynamic_entry (DT_JMPREL, 0))) + return FALSE; + + if (relocs + && (!add_dynamic_entry (DT_RELA, 0) + || !add_dynamic_entry (DT_RELASZ, 0) + || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))) + return FALSE; + + if (!info->shared && !add_dynamic_entry (DT_NIOS2_GP, 0)) + return FALSE; + + if ((info->flags & DF_TEXTREL) != 0 + && !add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } +#undef add_dynamic_entry + + return TRUE; +} + +/* Implement bfd_elf32_bfd_link_hash_table_create. */ +static struct bfd_link_hash_table * +nios2_elf32_link_hash_table_create (bfd *abfd) +{ + struct elf32_nios2_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf32_nios2_link_hash_table); + + ret = bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, + link_hash_newfunc, + sizeof (struct + elf32_nios2_link_hash_entry), + NIOS2_ELF_DATA)) + { + free (ret); + return NULL; + } + + ret->sdynbss = NULL; + ret->srelbss = NULL; + ret->sbss = NULL; + ret->tls_ldm_got.refcount = 0; + ret->sym_cache.abfd = NULL; + return &ret->root.root; +} + +/* Implement elf_backend_reloc_type_class. */ +static enum elf_reloc_type_class +nios2_elf32_reloc_type_class (const Elf_Internal_Rela *rela) +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_NIOS2_RELATIVE: + return reloc_class_relative; + case R_NIOS2_JUMP_SLOT: + return reloc_class_plt; + case R_NIOS2_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +/* Return 1 if target is one of ours. */ +static bfd_boolean +is_nios2_elf_target (const struct bfd_target *targ) +{ + return (targ == &bfd_elf32_littlenios2_vec + || targ == &bfd_elf32_bignios2_vec); +} + +/* Implement elf_backend_add_symbol_hook. + This hook is called by the linker when adding symbols from an object + file. We use it to put .comm items in .sbss, and not .bss. */ +static bfd_boolean +nios2_elf_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, + bfd_vma *valp) +{ + bfd *dynobj; + + if (sym->st_shndx == SHN_COMMON + && !info->relocatable + && sym->st_size <= elf_gp_size (abfd) + && is_nios2_elf_target (info->output_bfd->xvec)) + { + /* Common symbols less than or equal to -G nn bytes are automatically + put into .sbss. */ + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + if (htab->sbss == NULL) + { + flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; + + dynobj = elf_hash_table (info)->dynobj; + if (!dynobj) + dynobj = abfd; + + htab->sbss = bfd_make_section_anyway_with_flags (dynobj, ".sbss", + flags); + if (htab->sbss == NULL) + return FALSE; + } + + *secp = htab->sbss; + *valp = sym->st_size; + } + + return TRUE; +} + +/* Implement elf_backend_can_make_relative_eh_frame: + Decide whether to attempt to turn absptr or lsda encodings in + shared libraries into pcrel within the given input section. */ +static bfd_boolean +nios2_elf32_can_make_relative_eh_frame (bfd *input_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info + ATTRIBUTE_UNUSED, + asection *eh_frame_section + ATTRIBUTE_UNUSED) +{ + /* We can't use PC-relative encodings in the .eh_frame section. */ + return FALSE; +} + +/* Implement elf_backend_special_sections. */ +const struct bfd_elf_special_section elf32_nios2_special_sections[] = +{ + { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, + SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, + { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, + SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, + { NULL, 0, 0, 0, 0 } +}; + +#define ELF_ARCH bfd_arch_nios2 +#define ELF_TARGET_ID NIOS2_ELF_DATA +#define ELF_MACHINE_CODE EM_ALTERA_NIOS2 + +/* The Nios II MMU uses a 4K page size. */ + +#define ELF_MAXPAGESIZE 0x1000 + +#define bfd_elf32_bfd_link_hash_table_create \ + nios2_elf32_link_hash_table_create + +/* Relocation table lookup macros. */ + +#define bfd_elf32_bfd_reloc_type_lookup nios2_elf32_bfd_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup nios2_elf32_bfd_reloc_name_lookup + +/* JUMP_TABLE_LINK macros. */ + +/* elf_info_to_howto (using RELA relocations). */ + +#define elf_info_to_howto nios2_elf32_info_to_howto + +/* elf backend functions. */ + +#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_rela_normal 1 + +#define elf_backend_relocate_section nios2_elf32_relocate_section +#define elf_backend_section_flags nios2_elf32_section_flags +#define elf_backend_fake_sections nios2_elf32_fake_sections +#define elf_backend_check_relocs nios2_elf32_check_relocs + +#define elf_backend_gc_mark_hook nios2_elf32_gc_mark_hook +#define elf_backend_gc_sweep_hook nios2_elf32_gc_sweep_hook +#define elf_backend_create_dynamic_sections \ + nios2_elf32_create_dynamic_sections +#define elf_backend_finish_dynamic_symbol nios2_elf32_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + nios2_elf32_finish_dynamic_sections +#define elf_backend_adjust_dynamic_symbol nios2_elf32_adjust_dynamic_symbol +#define elf_backend_reloc_type_class nios2_elf32_reloc_type_class +#define elf_backend_size_dynamic_sections nios2_elf32_size_dynamic_sections +#define elf_backend_add_symbol_hook nios2_elf_add_symbol_hook +#define elf_backend_copy_indirect_symbol nios2_elf32_copy_indirect_symbol + +#define elf_backend_grok_prstatus nios2_grok_prstatus +#define elf_backend_grok_psinfo nios2_grok_psinfo + +#undef elf_backend_can_make_relative_eh_frame +#define elf_backend_can_make_relative_eh_frame \ + nios2_elf32_can_make_relative_eh_frame + +#define elf_backend_special_sections elf32_nios2_special_sections + +#define TARGET_LITTLE_SYM bfd_elf32_littlenios2_vec +#define TARGET_LITTLE_NAME "elf32-littlenios2" +#define TARGET_BIG_SYM bfd_elf32_bignios2_vec +#define TARGET_BIG_NAME "elf32-bignios2" + +#define elf_backend_got_header_size 12 + +#include "elf32-target.h" diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 20d6147..729fd11 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2370,6 +2370,40 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MSP430_16_BYTE", "BFD_RELOC_MSP430_2X_PCREL", "BFD_RELOC_MSP430_RL_PCREL", + "BFD_RELOC_NIOS2_S16", + "BFD_RELOC_NIOS2_U16", + "BFD_RELOC_NIOS2_CALL26", + "BFD_RELOC_NIOS2_IMM5", + "BFD_RELOC_NIOS2_CACHE_OPX", + "BFD_RELOC_NIOS2_IMM6", + "BFD_RELOC_NIOS2_IMM8", + "BFD_RELOC_NIOS2_HI16", + "BFD_RELOC_NIOS2_LO16", + "BFD_RELOC_NIOS2_HIADJ16", + "BFD_RELOC_NIOS2_GPREL", + "BFD_RELOC_NIOS2_UJMP", + "BFD_RELOC_NIOS2_CJMP", + "BFD_RELOC_NIOS2_CALLR", + "BFD_RELOC_NIOS2_ALIGN", + "BFD_RELOC_NIOS2_GOT16", + "BFD_RELOC_NIOS2_CALL16", + "BFD_RELOC_NIOS2_GOTOFF_LO", + "BFD_RELOC_NIOS2_GOTOFF_HA", + "BFD_RELOC_NIOS2_PCREL_LO", + "BFD_RELOC_NIOS2_PCREL_HA", + "BFD_RELOC_NIOS2_TLS_GD16", + "BFD_RELOC_NIOS2_TLS_LDM16", + "BFD_RELOC_NIOS2_TLS_LDO16", + "BFD_RELOC_NIOS2_TLS_IE16", + "BFD_RELOC_NIOS2_TLS_LE16", + "BFD_RELOC_NIOS2_TLS_DTPMOD", + "BFD_RELOC_NIOS2_TLS_DTPREL", + "BFD_RELOC_NIOS2_TLS_TPREL", + "BFD_RELOC_NIOS2_COPY", + "BFD_RELOC_NIOS2_GLOB_DAT", + "BFD_RELOC_NIOS2_JUMP_SLOT", + "BFD_RELOC_NIOS2_RELATIVE", + "BFD_RELOC_NIOS2_GOTOFF", "BFD_RELOC_IQ2000_OFFSET_16", "BFD_RELOC_IQ2000_OFFSET_21", "BFD_RELOC_IQ2000_UHI16", diff --git a/bfd/reloc.c b/bfd/reloc.c index 7a14be9..626c818 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -5665,6 +5665,77 @@ ENUMDOC msp430 specific relocation codes ENUM + BFD_RELOC_NIOS2_S16 +ENUMX + BFD_RELOC_NIOS2_U16 +ENUMX + BFD_RELOC_NIOS2_CALL26 +ENUMX + BFD_RELOC_NIOS2_IMM5 +ENUMX + BFD_RELOC_NIOS2_CACHE_OPX +ENUMX + BFD_RELOC_NIOS2_IMM6 +ENUMX + BFD_RELOC_NIOS2_IMM8 +ENUMX + BFD_RELOC_NIOS2_HI16 +ENUMX + BFD_RELOC_NIOS2_LO16 +ENUMX + BFD_RELOC_NIOS2_HIADJ16 +ENUMX + BFD_RELOC_NIOS2_GPREL +ENUMX + BFD_RELOC_NIOS2_UJMP +ENUMX + BFD_RELOC_NIOS2_CJMP +ENUMX + BFD_RELOC_NIOS2_CALLR +ENUMX + BFD_RELOC_NIOS2_ALIGN +ENUMX + BFD_RELOC_NIOS2_GOT16 +ENUMX + BFD_RELOC_NIOS2_CALL16 +ENUMX + BFD_RELOC_NIOS2_GOTOFF_LO +ENUMX + BFD_RELOC_NIOS2_GOTOFF_HA +ENUMX + BFD_RELOC_NIOS2_PCREL_LO +ENUMX + BFD_RELOC_NIOS2_PCREL_HA +ENUMX + BFD_RELOC_NIOS2_TLS_GD16 +ENUMX + BFD_RELOC_NIOS2_TLS_LDM16 +ENUMX + BFD_RELOC_NIOS2_TLS_LDO16 +ENUMX + BFD_RELOC_NIOS2_TLS_IE16 +ENUMX + BFD_RELOC_NIOS2_TLS_LE16 +ENUMX + BFD_RELOC_NIOS2_TLS_DTPMOD +ENUMX + BFD_RELOC_NIOS2_TLS_DTPREL +ENUMX + BFD_RELOC_NIOS2_TLS_TPREL +ENUMX + BFD_RELOC_NIOS2_COPY +ENUMX + BFD_RELOC_NIOS2_GLOB_DAT +ENUMX + BFD_RELOC_NIOS2_JUMP_SLOT +ENUMX + BFD_RELOC_NIOS2_RELATIVE +ENUMX + BFD_RELOC_NIOS2_GOTOFF +ENUMDOC + Relocations used by the Altera Nios II core. + +ENUM BFD_RELOC_IQ2000_OFFSET_16 ENUMX BFD_RELOC_IQ2000_OFFSET_21 diff --git a/bfd/targets.c b/bfd/targets.c index 17553eb..c9fbbc2 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -607,6 +607,7 @@ extern const bfd_target bfd_elf32_bigarm_vxworks_vec; extern const bfd_target bfd_elf32_bigmips_vec; extern const bfd_target bfd_elf32_bigmips_vxworks_vec; extern const bfd_target bfd_elf32_bigmoxie_vec; +extern const bfd_target bfd_elf32_bignios2_vec; extern const bfd_target bfd_elf32_cr16_vec; extern const bfd_target bfd_elf32_cr16c_vec; extern const bfd_target bfd_elf32_cris_vec; @@ -646,6 +647,7 @@ extern const bfd_target bfd_elf32_littlearm_vxworks_vec; extern const bfd_target bfd_elf32_littlemips_vec; extern const bfd_target bfd_elf32_littlemips_vxworks_vec; extern const bfd_target bfd_elf32_littlemoxie_vec; +extern const bfd_target bfd_elf32_littlenios2_vec; extern const bfd_target bfd_elf32_m32c_vec; extern const bfd_target bfd_elf32_m32r_vec; extern const bfd_target bfd_elf32_m32rle_vec; @@ -984,6 +986,7 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_bigmips_vec, &bfd_elf32_bigmips_vxworks_vec, &bfd_elf32_bigmoxie_vec, + &bfd_elf32_bignios2_vec, &bfd_elf32_cr16_vec, &bfd_elf32_cr16c_vec, &bfd_elf32_cris_vec, @@ -1025,6 +1028,7 @@ static const bfd_target * const _bfd_target_vector[] = &bfd_elf32_littlemips_vec, &bfd_elf32_littlemips_vxworks_vec, &bfd_elf32_littlemoxie_vec, + &bfd_elf32_littlenios2_vec, &bfd_elf32_m32c_vec, &bfd_elf32_m32r_vec, &bfd_elf32_m32rle_vec, diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 2eedde7..9a0701b 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,18 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * readelf.c: Include elf/nios2.h. + (dump_relocations): Add case for EM_ALTERA_NIOS2. + (get_nios2_dynamic_type): New. + (get_dynamic_type): Add case for EM_ALTERA_NIOS2. + (is_32bit_abs_reloc): Fix EM_ALTERA_NIOS2 case. + (is_16bit_abs_reloc): Likewise. + (is_none_reloc): Add EM_ALTERA_NIOS2 and EM_NIOS32 cases. + * NEWS: Note Altera Nios II support. + * MAINTAINERS: Add Nios II maintainers. + 2013-01-29 Xi Wang <xi.wang@gmail.com> * readelf.c (process_version_sections): Fix overflow checks to diff --git a/binutils/MAINTAINERS b/binutils/MAINTAINERS index f887dcd..2a1ac61 100644 --- a/binutils/MAINTAINERS +++ b/binutils/MAINTAINERS @@ -107,6 +107,8 @@ responsibility among the other maintainers. Moxie Anthony Green <green@moxielogic.com> MSP430 Dmitry Diky <diwil@spec.ru> NetBSD support Matt Thomas <matt@netbsd.org> + Nios II Sandra Loosemore <sandra@codesourcery.com> + Nios II Andrew Jenner <andrew@codesourcery.com> PPC Geoff Keating <geoffk@geoffk.org> PPC Alan Modra <amodra@gmail.com> PPC vector ext Aldy Hernandez <aldyh@redhat.com> diff --git a/binutils/NEWS b/binutils/NEWS index 2d36dbc..9140043 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,7 @@ -*- text -*- +* Add support for Altera Nios II. + Changes in 2.23: * Add support for the VLE extension to the PowerPC architecture. diff --git a/binutils/readelf.c b/binutils/readelf.c index ae211a7..7710079 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -153,6 +153,8 @@ #include "elf/xstormy16.h" #include "elf/xtensa.h" +#include "elf/nios2.h" + #include "getopt.h" #include "libiberty.h" #include "safe-ctype.h" @@ -1288,6 +1290,10 @@ dump_relocations (FILE * file, case EM_XGATE: rtype = elf_xgate_reloc_type (type); break; + + case EM_ALTERA_NIOS2: + rtype = elf_nios2_reloc_type (type); + break; } if (rtype == NULL) @@ -1687,6 +1693,17 @@ get_tic6x_dynamic_type (unsigned long type) } static const char * +get_nios2_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_NIOS2_GP: return "NIOS2_GP"; + default: + return NULL; + } +} + +static const char * get_dynamic_type (unsigned long type) { static char buff[64]; @@ -1800,6 +1817,9 @@ get_dynamic_type (unsigned long type) case EM_TI_C6000: result = get_tic6x_dynamic_type (type); break; + case EM_ALTERA_NIOS2: + result = get_nios2_dynamic_type (type); + break; default: result = NULL; break; @@ -10074,6 +10094,7 @@ is_32bit_abs_reloc (unsigned int reloc_type) case EM_MT: return reloc_type == 2; /* R_MT_32. */ case EM_ALTERA_NIOS2: + return reloc_type == 12; /* R_NIOS2_BFD_RELOC_32. */ case EM_NIOS32: return reloc_type == 1; /* R_NIOS_32. */ case EM_OPENRISC: @@ -10324,6 +10345,7 @@ is_16bit_abs_reloc (unsigned int reloc_type) case EM_MSP430_OLD: return reloc_type == 5; /* R_MSP430_16_BYTE. */ case EM_ALTERA_NIOS2: + return reloc_type == 13; /* R_NIOS2_BFD_RELOC_16. */ case EM_NIOS32: return reloc_type == 9; /* R_NIOS_16. */ case EM_TI_C6000: @@ -10380,6 +10402,8 @@ is_none_reloc (unsigned int reloc_type) case EM_TILEPRO: /* R_TILEPRO_NONE. */ case EM_XC16X: case EM_C166: /* R_XC16X_NONE. */ + case EM_ALTERA_NIOS2: /* R_NIOS2_NONE. */ + case EM_NIOS32: /* R_NIOS_NONE. */ return reloc_type == 0; case EM_AARCH64: return reloc_type == 0 || reloc_type == 256; diff --git a/gas/ChangeLog b/gas/ChangeLog index d064176..01ac44d 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,23 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * Makefile.am (TARGET_CPU_CFILES): Add config/tc-nios2.c. + (TARGET_CPU_HFILES): Add config/tc-nios2.h. + * Makefile.in: Regenerated. + * configure.tgt: Add case for nios2*-linux*. + * config/obj-elf.c: Conditionally include elf/nios2.h. + * config/tc-nios2.c: New file. + * config/tc-nios2.h: New file. + * doc/Makefile.am (CPU_DOCS): Add c-nios2.texi. + * doc/Makefile.in: Regenerated. + * doc/all.texi: Set NIOSII. + * doc/as.texinfo (Overview): Add Nios II options. + (Machine Dependencies): Include c-nios2.texi. + * doc/c-nios2.texi: New file. + * NEWS: Note Altera Nios II support. + 2013-02-06 Alan Modra <amodra@gmail.com> PR gas/14255 diff --git a/gas/Makefile.am b/gas/Makefile.am index 7729d4a..5ed9d2a 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -164,6 +164,7 @@ TARGET_CPU_CFILES = \ config/tc-moxie.c \ config/tc-msp430.c \ config/tc-mt.c \ + config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-openrisc.c \ config/tc-or32.c \ @@ -234,6 +235,7 @@ TARGET_CPU_HFILES = \ config/tc-mn10300.h \ config/tc-msp430.h \ config/tc-mt.h \ + config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-openrisc.h \ config/tc-or32.h \ diff --git a/gas/Makefile.in b/gas/Makefile.in index c2a646c..c71e284 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -433,6 +433,7 @@ TARGET_CPU_CFILES = \ config/tc-moxie.c \ config/tc-msp430.c \ config/tc-mt.c \ + config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-openrisc.c \ config/tc-or32.c \ @@ -503,6 +504,7 @@ TARGET_CPU_HFILES = \ config/tc-mn10300.h \ config/tc-msp430.h \ config/tc-mt.h \ + config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-openrisc.h \ config/tc-or32.h \ @@ -855,6 +857,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-moxie.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-msp430.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-mt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-nios2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-ns32k.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-openrisc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-or32.Po@am__quote@ @@ -1468,6 +1471,20 @@ tc-mt.obj: config/tc-mt.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-mt.obj `if test -f 'config/tc-mt.c'; then $(CYGPATH_W) 'config/tc-mt.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-mt.c'; fi` +tc-nios2.o: config/tc-nios2.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-nios2.o -MD -MP -MF $(DEPDIR)/tc-nios2.Tpo -c -o tc-nios2.o `test -f 'config/tc-nios2.c' || echo '$(srcdir)/'`config/tc-nios2.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-nios2.Tpo $(DEPDIR)/tc-nios2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-nios2.c' object='tc-nios2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-nios2.o `test -f 'config/tc-nios2.c' || echo '$(srcdir)/'`config/tc-nios2.c + +tc-nios2.obj: config/tc-nios2.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-nios2.obj -MD -MP -MF $(DEPDIR)/tc-nios2.Tpo -c -o tc-nios2.obj `if test -f 'config/tc-nios2.c'; then $(CYGPATH_W) 'config/tc-nios2.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-nios2.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-nios2.Tpo $(DEPDIR)/tc-nios2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-nios2.c' object='tc-nios2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-nios2.obj `if test -f 'config/tc-nios2.c'; then $(CYGPATH_W) 'config/tc-nios2.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-nios2.c'; fi` + tc-ns32k.o: config/tc-ns32k.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-ns32k.o -MD -MP -MF $(DEPDIR)/tc-ns32k.Tpo -c -o tc-ns32k.o `test -f 'config/tc-ns32k.c' || echo '$(srcdir)/'`config/tc-ns32k.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-ns32k.Tpo $(DEPDIR)/tc-ns32k.Po @@ -1,5 +1,7 @@ -*- text -*- +* Add support for Altera Nios II. + * Add support for the Imagination Technologies Meta processor. * Add support for the v850e3v5. diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index 6450328..3377261 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -62,6 +62,10 @@ #include "elf/mep.h" #endif +#ifdef TC_NIOS2 +#include "elf/nios2.h" +#endif + static void obj_elf_line (int); static void obj_elf_size (int); static void obj_elf_type (int); diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c new file mode 100644 index 0000000..841c454 --- /dev/null +++ b/gas/config/tc-nios2.c @@ -0,0 +1,3067 @@ +/* Altera Nios II assembler. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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 "opcode/nios2.h" +#include "elf/nios2.h" +#include "tc-nios2.h" +#include "bfd.h" +#include "dwarf2dbg.h" +#include "subsegs.h" +#include "safe-ctype.h" +#include "dw2gencfi.h" + +#ifndef OBJ_ELF +/* We are not supporting any other target so we throw a compile time error. */ +OBJ_ELF not defined +#endif + +/* We can choose our endianness at run-time, regardless of configuration. */ +extern int target_big_endian; + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful. */ +const char comment_chars[] = "#"; + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output. */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that C style comments are always supported. */ +const char line_comment_chars[] = "#"; + +/* This array holds machine specific line separator characters. */ +const char line_separator_chars[] = ";"; + +/* Chars that can be used to separate mant from exp in floating point nums. */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant. */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. */ + +/* Machine-dependent command-line options. */ + +const char *md_shortopts = "r"; + +struct option md_longopts[] = { +#define OPTION_RELAX_ALL (OPTION_MD_BASE + 0) + {"relax-all", no_argument, NULL, OPTION_RELAX_ALL}, +#define OPTION_NORELAX (OPTION_MD_BASE + 1) + {"no-relax", no_argument, NULL, OPTION_NORELAX}, +#define OPTION_RELAX_SECTION (OPTION_MD_BASE + 2) + {"relax-section", no_argument, NULL, OPTION_RELAX_SECTION}, +#define OPTION_EB (OPTION_MD_BASE + 3) + {"EB", no_argument, NULL, OPTION_EB}, +#define OPTION_EL (OPTION_MD_BASE + 4) + {"EL", no_argument, NULL, OPTION_EL} +}; + +size_t md_longopts_size = sizeof (md_longopts); + +/* The assembler supports three different relaxation modes, controlled by + command-line options. */ +typedef enum +{ + relax_section = 0, + relax_none, + relax_all +} relax_optionT; + +/* Struct contains all assembler options set with .set. */ +struct +{ + /* .set noat -> noat = 1 allows assembly code to use at without warning + and macro expansions generate a warning. + .set at -> noat = 0, assembly code using at warn but macro expansions + do not generate warnings. */ + bfd_boolean noat; + + /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without + warning. + .set break -> nobreak = 0, assembly code using ba,bt warns. */ + bfd_boolean nobreak; + + /* .cmd line option -relax-all allows all branches and calls to be replaced + with longer versions. + -no-relax inhibits branch/call conversion. + The default value is relax_section, which relaxes branches within + a section. */ + relax_optionT relax; + +} nios2_as_options = {FALSE, FALSE, relax_section}; + + +typedef struct nios2_insn_reloc +{ + /* Any expression in the instruction is parsed into this field, + which is passed to fix_new_exp() to generate a fixup. */ + expressionS reloc_expression; + + /* The type of the relocation to be applied. */ + bfd_reloc_code_real_type reloc_type; + + /* PC-relative. */ + unsigned int reloc_pcrel; + + /* The next relocation to be applied to the instruction. */ + struct nios2_insn_reloc *reloc_next; +} nios2_insn_relocS; + +/* This struct is used to hold state when assembling instructions. */ +typedef struct nios2_insn_info +{ + /* Assembled instruction. */ + unsigned long insn_code; + /* Pointer to the relevant bit of the opcode table. */ + const struct nios2_opcode *insn_nios2_opcode; + /* After parsing ptrs to the tokens in the instruction fill this array + it is terminated with a null pointer (hence the first +1). + The second +1 is because in some parts of the code the opcode + is not counted as a token, but still placed in this array. */ + const char *insn_tokens[NIOS2_MAX_INSN_TOKENS + 1 + 1]; + + /* This holds information used to generate fixups + and eventually relocations if it is not null. */ + nios2_insn_relocS *insn_reloc; +} nios2_insn_infoS; + +/* This struct associates an argument assemble function with + an argument syntax string. Used by the assembler to find out + how to parse and assemble a set of instruction operands and + return the instruction field values. */ +typedef struct nios2_arg_info +{ + const char *args; + void (*assemble_args_func) (nios2_insn_infoS *insn_info); +} nios2_arg_infoS; + +/* This struct is used to convert Nios II pseudo-ops into the + corresponding real op. */ +typedef struct nios2_ps_insn_info +{ + /* Map this pseudo_op... */ + const char *pseudo_insn; + + /* ...to this real instruction. */ + const char *insn; + + /* Call this function to modify the operands.... */ + void (*arg_modifer_func) (char ** parsed_args, const char *arg, int num, + int start); + + /* ...with these arguments. */ + const char *arg_modifier; + int num; + int index; + + /* If arg_modifier_func allocates new memory, provide this function + to free it afterwards. */ + void (*arg_cleanup_func) (char **parsed_args, int num, int start); +} nios2_ps_insn_infoS; + +/* Opcode hash table. */ +static struct hash_control *nios2_opcode_hash = NULL; +#define nios2_opcode_lookup(NAME) \ + ((struct nios2_opcode *) hash_find (nios2_opcode_hash, (NAME))) + +/* Register hash table. */ +static struct hash_control *nios2_reg_hash = NULL; +#define nios2_reg_lookup(NAME) \ + ((struct nios2_reg *) hash_find (nios2_reg_hash, (NAME))) + +/* Parse args hash table. */ +static struct hash_control *nios2_arg_hash = NULL; +#define nios2_arg_lookup(NAME) \ + ((nios2_arg_infoS *) hash_find (nios2_arg_hash, (NAME))) + +/* Pseudo-op hash table. */ +static struct hash_control *nios2_ps_hash = NULL; +#define nios2_ps_lookup(NAME) \ + ((nios2_ps_insn_infoS *) hash_find (nios2_ps_hash, (NAME))) + +/* The known current alignment of the current section. */ +static int nios2_current_align; +static segT nios2_current_align_seg; + +static int nios2_auto_align_on = 1; + +/* The last seen label in the current section. This is used to auto-align + labels preceeding instructions. */ +static symbolS *nios2_last_label; + +#ifdef OBJ_ELF +/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ +symbolS *GOT_symbol; +#endif + + +/** Utility routines. */ +/* Function md_chars_to_number takes the sequence of + bytes in buf and returns the corresponding value + in an int. n must be 1, 2 or 4. */ +static valueT +md_chars_to_number (char *buf, int n) +{ + int i; + valueT val; + + gas_assert (n == 1 || n == 2 || n == 4); + + val = 0; + if (target_big_endian) + for (i = 0; i < n; ++i) + val = val | ((buf[i] & 0xff) << 8 * (n - (i + 1))); + else + for (i = 0; i < n; ++i) + val = val | ((buf[i] & 0xff) << 8 * i); + return val; +} + + +/* This function turns a C long int, short int or char + into the series of bytes that represent the number + on the target machine. */ +void +md_number_to_chars (char *buf, valueT val, int n) +{ + gas_assert (n == 1 || n == 2 || n == 4 || n == 8); + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); +} + +/* Turn a string in input_line_pointer into a floating point constant + of type TYPE, and store the appropriate bytes in *LITP. The number + of LITTLENUMS emitted is stored in *SIZEP. An error message is + returned, or NULL on OK. */ +char * +md_atof (int type, char *litP, int *sizeP) +{ + int prec; + LITTLENUM_TYPE words[4]; + char *t; + int i; + + switch (type) + { + case 'f': + prec = 2; + break; + case 'd': + prec = 4; + break; + default: + *sizeP = 0; + return _("bad call to md_atof"); + } + + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * 2; + + if (! target_big_endian) + for (i = prec - 1; i >= 0; i--, litP += 2) + md_number_to_chars (litP, (valueT) words[i], 2); + else + for (i = 0; i < prec; i++, litP += 2) + md_number_to_chars (litP, (valueT) words[i], 2); + + return NULL; +} + +/* Return true if STR starts with PREFIX, which should be a string literal. */ +#define strprefix(STR, PREFIX) \ + (strncmp ((STR), PREFIX, strlen (PREFIX)) == 0) + +/* Return true if STR is prefixed with a control register name. */ +static int +nios2_control_register_arg_p (const char *str) +{ + return (strprefix (str, "ctl") + || strprefix (str, "cpuid") + || strprefix (str, "status") + || strprefix (str, "estatus") + || strprefix (str, "bstatus") + || strprefix (str, "ienable") + || strprefix (str, "ipending") + || strprefix (str, "exception") + || strprefix (str, "pteaddr") + || strprefix (str, "tlbacc") + || strprefix (str, "tlbmisc") + || strprefix (str, "fstatus") + || strprefix (str, "config") + || strprefix (str, "mpubase") + || strprefix (str, "mpuacc") + || strprefix (str, "badaddr")); +} + +/* Return true if STR is prefixed with a special relocation operator. */ +static int +nios2_special_relocation_p (const char *str) +{ + return (strprefix (str, "%lo") + || strprefix (str, "%hi") + || strprefix (str, "%hiadj") + || strprefix (str, "%gprel") + || strprefix (str, "%got") + || strprefix (str, "%call") + || strprefix (str, "%gotoff_lo") + || strprefix (str, "%gotoff_hiadj") + || strprefix (str, "%tls_gd") + || strprefix (str, "%tls_ldm") + || strprefix (str, "%tls_ldo") + || strprefix (str, "%tls_ie") + || strprefix (str, "%tls_le") + || strprefix (str, "%gotoff")); +} + +/* Checks whether the register name is a coprocessor + register - returns TRUE if it is, FALSE otherwise. */ +static bfd_boolean +nios2_coproc_reg (const char *reg_name) +{ + gas_assert (reg_name != NULL); + + /* Check that we do have a valid register name and that it is a + coprocessor register. + It must begin with c, not be a control register, and be a valid + register name. */ + if (strprefix (reg_name, "c") + && !strprefix (reg_name, "ctl") + && hash_find (nios2_reg_hash, reg_name) != NULL) + return TRUE; + else + return FALSE; +} + +/* nop fill pattern for text section. */ +static char const nop[4] = { 0x3a, 0x88, 0x01, 0x00 }; + +/* Handles all machine-dependent alignment needs. */ +static void +nios2_align (int log_size, const char *pfill, symbolS *label) +{ + int align; + long max_alignment = 15; + + /* The front end is prone to changing segments out from under us + temporarily when -g is in effect. */ + int switched_seg_p = (nios2_current_align_seg != now_seg); + + align = log_size; + if (align > max_alignment) + { + align = max_alignment; + as_bad (_("Alignment too large: %d. assumed"), align); + } + else if (align < 0) + { + as_warn (_("Alignment negative: 0 assumed")); + align = 0; + } + + if (align != 0) + { + if (subseg_text_p (now_seg) && align >= 2) + { + /* First, make sure we're on a four-byte boundary, in case + someone has been putting .byte values the text section. */ + if (nios2_current_align < 2 || switched_seg_p) + frag_align (2, 0, 0); + + /* Now fill in the alignment pattern. */ + if (pfill != NULL) + frag_align_pattern (align, pfill, sizeof nop, 0); + else + frag_align (align, 0, 0); + } + else + frag_align (align, 0, 0); + + if (!switched_seg_p) + nios2_current_align = align; + + /* If the last label was in a different section we can't align it. */ + if (label != NULL && !switched_seg_p) + { + symbolS *sym; + int label_seen = FALSE; + struct frag *old_frag; + valueT old_value; + valueT new_value; + + gas_assert (S_GET_SEGMENT (label) == now_seg); + + old_frag = symbol_get_frag (label); + old_value = S_GET_VALUE (label); + new_value = (valueT) frag_now_fix (); + + /* It is possible to have more than one label at a particular + address, especially if debugging is enabled, so we must + take care to adjust all the labels at this address in this + fragment. To save time we search from the end of the symbol + list, backwards, since the symbols we are interested in are + almost certainly the ones that were most recently added. + Also to save time we stop searching once we have seen at least + one matching label, and we encounter a label that is no longer + in the target fragment. Note, this search is guaranteed to + find at least one match when sym == label, so no special case + code is necessary. */ + for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym)) + if (symbol_get_frag (sym) == old_frag + && S_GET_VALUE (sym) == old_value) + { + label_seen = TRUE; + symbol_set_frag (sym, frag_now); + S_SET_VALUE (sym, new_value); + } + else if (label_seen && symbol_get_frag (sym) != old_frag) + break; + } + record_alignment (now_seg, align); + } +} + + +/** Support for self-check mode. */ + +/* Mode of the assembler. */ +typedef enum +{ + NIOS2_MODE_ASSEMBLE, /* Ordinary operation. */ + NIOS2_MODE_TEST /* Hidden mode used for self testing. */ +} NIOS2_MODE; + +static NIOS2_MODE nios2_mode = NIOS2_MODE_ASSEMBLE; + +/* This function is used to in self-checking mode + to check the assembled instruction + opcode should be the assembled opcode, and exp_opcode + the parsed string representing the expected opcode. */ +static void +nios2_check_assembly (unsigned int opcode, const char *exp_opcode) +{ + if (nios2_mode == NIOS2_MODE_TEST) + { + if (exp_opcode == NULL) + as_bad (_("expecting opcode string in self test mode")); + else if (opcode != strtoul (exp_opcode, NULL, 16)) + as_bad (_("assembly 0x%08x, expected %s"), opcode, exp_opcode); + } +} + + +/** Support for machine-dependent assembler directives. */ +/* Handle the .align pseudo-op. This aligns to a power of two. It + also adjusts any current instruction label. We treat this the same + way the MIPS port does: .align 0 turns off auto alignment. */ +static void +s_nios2_align (int ignore ATTRIBUTE_UNUSED) +{ + int align; + char fill; + const char *pfill = NULL; + long max_alignment = 15; + + align = get_absolute_expression (); + if (align > max_alignment) + { + align = max_alignment; + as_bad (_("Alignment too large: %d. assumed"), align); + } + else if (align < 0) + { + as_warn (_("Alignment negative: 0 assumed")); + align = 0; + } + + if (*input_line_pointer == ',') + { + input_line_pointer++; + fill = get_absolute_expression (); + pfill = (const char *) &fill; + } + else if (subseg_text_p (now_seg)) + pfill = (const char *) &nop; + else + { + pfill = NULL; + nios2_last_label = NULL; + } + + if (align != 0) + { + nios2_auto_align_on = 1; + nios2_align (align, pfill, nios2_last_label); + nios2_last_label = NULL; + } + else + nios2_auto_align_on = 0; + + demand_empty_rest_of_line (); +} + +/* Handle the .text pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ +static void +s_nios2_text (int i) +{ + s_text (i); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} + +/* Handle the .data pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ +static void +s_nios2_data (int i) +{ + s_data (i); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} + +/* Handle the .section pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ +static void +s_nios2_section (int ignore) +{ + obj_elf_section (ignore); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} + +/* Explicitly unaligned cons. */ +static void +s_nios2_ucons (int nbytes) +{ + int hold; + hold = nios2_auto_align_on; + nios2_auto_align_on = 0; + cons (nbytes); + nios2_auto_align_on = hold; +} + +/* Handle the .sdata directive. */ +static void +s_nios2_sdata (int ignore ATTRIBUTE_UNUSED) +{ + get_absolute_expression (); /* Ignored. */ + subseg_new (".sdata", 0); + demand_empty_rest_of_line (); +} + +/* .set sets assembler options eg noat/at and is also used + to set symbol values (.equ, .equiv ). */ +static void +s_nios2_set (int equiv) +{ + char *directive = input_line_pointer; + char delim = get_symbol_end (); + char *endline = input_line_pointer; + *endline = delim; + + /* We only want to handle ".set XXX" if the + user has tried ".set XXX, YYY" they are not + trying a directive. This prevents + us from polluting the name space. */ + SKIP_WHITESPACE (); + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + bfd_boolean done = TRUE; + *endline = 0; + + if (!strcmp (directive, "noat")) + nios2_as_options.noat = TRUE; + else if (!strcmp (directive, "at")) + nios2_as_options.noat = FALSE; + else if (!strcmp (directive, "nobreak")) + nios2_as_options.nobreak = TRUE; + else if (!strcmp (directive, "break")) + nios2_as_options.nobreak = FALSE; + else if (!strcmp (directive, "norelax")) + nios2_as_options.relax = relax_none; + else if (!strcmp (directive, "relaxsection")) + nios2_as_options.relax = relax_section; + else if (!strcmp (directive, "relaxall")) + nios2_as_options.relax = relax_all; + else + done = FALSE; + + if (done) + { + *endline = delim; + demand_empty_rest_of_line (); + return; + } + } + + /* If we fall through to here, either we have ".set XXX, YYY" + or we have ".set XXX" where XXX is unknown or we have + a syntax error. */ + input_line_pointer = directive; + *endline = delim; + s_set (equiv); +} + +/* Machine-dependent assembler directives. + Format of each entry is: + { "directive", handler_func, param } */ +const pseudo_typeS md_pseudo_table[] = { + {"align", s_nios2_align, 0}, + {"text", s_nios2_text, 0}, + {"data", s_nios2_data, 0}, + {"section", s_nios2_section, 0}, + {"section.s", s_nios2_section, 0}, + {"sect", s_nios2_section, 0}, + {"sect.s", s_nios2_section, 0}, + /* .dword and .half are included for compatibility with MIPS. */ + {"dword", cons, 8}, + {"half", cons, 2}, + /* NIOS2 native word size is 4 bytes, so we override + the GAS default of 2. */ + {"word", cons, 4}, + /* Explicitly unaligned directives. */ + {"2byte", s_nios2_ucons, 2}, + {"4byte", s_nios2_ucons, 4}, + {"8byte", s_nios2_ucons, 8}, + {"16byte", s_nios2_ucons, 16}, +#ifdef OBJ_ELF + {"sdata", s_nios2_sdata, 0}, +#endif + {"set", s_nios2_set, 0}, + {NULL, NULL, 0} +}; + + +/** Relaxation support. */ + +/* We support two relaxation modes: a limited PC-relative mode with + -relax-section (the default), and an absolute jump mode with -relax-all. + + Nios II PC-relative branch instructions only support 16-bit offsets. + And, there's no good way to add a 32-bit constant to the PC without + using two registers. + + To deal with this, for the pc-relative relaxation mode we convert + br label + into a series of 16-bit adds, like: + nextpc at + addi at, at, 32767 + ... + addi at, at, remainder + jmp at + + Similarly, conditional branches are converted from + b(condition) r, s, label + into a series like: + b(opposite condition) r, s, skip + nextpc at + addi at, at, 32767 + ... + addi at, at, remainder + jmp at + skip: + + The compiler can do a better job, either by converting the branch + directly into a JMP (going through the GOT for PIC) or by allocating + a second register for the 32-bit displacement. + + For the -relax-all relaxation mode, the conversions are + movhi at, %hi(symbol+offset) + ori at, %lo(symbol+offset) + jmp at + and + b(opposite condition), r, s, skip + movhi at, %hi(symbol+offset) + ori at, %lo(symbol+offset) + jmp at + skip: + respectively. +*/ + +/* Arbitrarily limit the number of addis we can insert; we need to be able + to specify the maximum growth size for each frag that contains a + relaxable branch. There's no point in specifying a huge number here + since that means the assembler needs to allocate that much extra + memory for every branch, and almost no real code will ever need it. + Plus, as already noted a better solution is to just use a jmp, or + allocate a second register to hold a 32-bit displacement. + FIXME: Rather than making this a constant, it could be controlled by + a command-line argument. */ +#define RELAX_MAX_ADDI 32 + +/* The fr_subtype field represents the target-specific relocation state. + It has type relax_substateT (unsigned int). We use it to track the + number of addis necessary, plus a bit to track whether this is a + conditional branch. + Regardless of the smaller RELAX_MAX_ADDI limit, we reserve 16 bits + in the fr_subtype to encode the number of addis so that the whole + theoretically-valid range is representable. + For the -relax-all mode, N = 0 represents an in-range branch and N = 1 + represents a branch that needs to be relaxed. */ +#define UBRANCH (0 << 16) +#define CBRANCH (1 << 16) +#define IS_CBRANCH(SUBTYPE) ((SUBTYPE) & CBRANCH) +#define IS_UBRANCH(SUBTYPE) (!IS_CBRANCH (SUBTYPE)) +#define UBRANCH_SUBTYPE(N) (UBRANCH | (N)) +#define CBRANCH_SUBTYPE(N) (CBRANCH | (N)) +#define SUBTYPE_ADDIS(SUBTYPE) ((SUBTYPE) & 0xffff) + +/* For the -relax-section mode, unconditional branches require 2 extra i + nstructions besides the addis, conditional branches require 3. */ +#define UBRANCH_ADDIS_TO_SIZE(N) (((N) + 2) * 4) +#define CBRANCH_ADDIS_TO_SIZE(N) (((N) + 3) * 4) + +/* For the -relax-all mode, unconditional branches require 3 instructions + and conditional branches require 4. */ +#define UBRANCH_JUMP_SIZE 12 +#define CBRANCH_JUMP_SIZE 16 + +/* Maximum sizes of relaxation sequences. */ +#define UBRANCH_MAX_SIZE \ + (nios2_as_options.relax == relax_all \ + ? UBRANCH_JUMP_SIZE \ + : UBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI)) +#define CBRANCH_MAX_SIZE \ + (nios2_as_options.relax == relax_all \ + ? CBRANCH_JUMP_SIZE \ + : CBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI)) + +/* Register number of AT, the assembler temporary. */ +#define AT_REGNUM 1 + +/* Determine how many bytes are required to represent the sequence + indicated by SUBTYPE. */ +static int +nios2_relax_subtype_size (relax_substateT subtype) +{ + int n = SUBTYPE_ADDIS (subtype); + if (n == 0) + /* Regular conditional/unconditional branch instruction. */ + return 4; + else if (nios2_as_options.relax == relax_all) + return (IS_CBRANCH (subtype) ? CBRANCH_JUMP_SIZE : UBRANCH_JUMP_SIZE); + else if (IS_CBRANCH (subtype)) + return CBRANCH_ADDIS_TO_SIZE (n); + else + return UBRANCH_ADDIS_TO_SIZE (n); +} + +/* Estimate size of fragp before relaxation. + This could also examine the offset in fragp and adjust + fragp->fr_subtype, but we will do that in nios2_relax_frag anyway. */ +int +md_estimate_size_before_relax (fragS *fragp, segT segment ATTRIBUTE_UNUSED) +{ + return nios2_relax_subtype_size (fragp->fr_subtype); +} + +/* Implement md_relax_frag, returning the change in size of the frag. */ +long +nios2_relax_frag (segT segment, fragS *fragp, long stretch) +{ + addressT target = fragp->fr_offset; + relax_substateT subtype = fragp->fr_subtype; + symbolS *symbolp = fragp->fr_symbol; + + if (symbolp) + { + fragS *sym_frag = symbol_get_frag (symbolp); + offsetT offset; + int n; + + target += S_GET_VALUE (symbolp); + + /* See comments in write.c:relax_frag about handling of stretch. */ + if (stretch != 0 + && sym_frag->relax_marker != fragp->relax_marker) + { + if (stretch < 0 || sym_frag->region == fragp->region) + target += stretch; + else if (target < fragp->fr_address) + target = fragp->fr_next->fr_address + stretch; + } + + /* We subtract 4 because all pc relative branches are + from the next instruction. */ + offset = target - fragp->fr_address - fragp->fr_fix - 4; + if (offset >= -32768 && offset <= 32764) + /* Fits in PC-relative branch. */ + n = 0; + else if (nios2_as_options.relax == relax_all) + /* Convert to jump. */ + n = 1; + else if (nios2_as_options.relax == relax_section + && S_GET_SEGMENT (symbolp) == segment + && S_IS_DEFINED (symbolp)) + /* Attempt a PC-relative relaxation on a branch to a defined + symbol in the same segment. */ + { + /* The relaxation for conditional branches is offset by 4 + bytes because we insert the inverted branch around the + sequence. */ + if (IS_CBRANCH (subtype)) + offset = offset - 4; + if (offset > 0) + n = offset / 32767 + 1; + else + n = offset / -32768 + 1; + + /* Bail out immediately if relaxation has failed. If we try to + defer the diagnostic to md_convert_frag, some pathological test + cases (e.g. gcc/testsuite/gcc.c-torture/compile/20001226-1.c) + apparently never converge. By returning 0 here we could pretend + to the caller that nothing has changed, but that leaves things + in an inconsistent state when we get to md_convert_frag. */ + if (n > RELAX_MAX_ADDI) + { + as_bad_where (fragp->fr_file, fragp->fr_line, + _("branch offset out of range\n")); + as_fatal (_("branch relaxation failed\n")); + } + } + else + /* We cannot handle this case, diagnose overflow later. */ + return 0; + + if (IS_CBRANCH (subtype)) + fragp->fr_subtype = CBRANCH_SUBTYPE (n); + else + fragp->fr_subtype = UBRANCH_SUBTYPE (n); + + return (nios2_relax_subtype_size (fragp->fr_subtype) + - nios2_relax_subtype_size (subtype)); + } + + /* If we got here, it's probably an error. */ + return 0; +} + + +/* Complete fragp using the data from the relaxation pass. */ +void +md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED, + fragS *fragp) +{ + char *buffer = fragp->fr_literal + fragp->fr_fix; + relax_substateT subtype = fragp->fr_subtype; + int n = SUBTYPE_ADDIS (subtype); + addressT target = fragp->fr_offset; + symbolS *symbolp = fragp->fr_symbol; + offsetT offset; + unsigned int addend_mask, addi_mask; + offsetT addend, remainder; + int i; + + /* If we didn't or can't relax, this is a regular branch instruction. + We just need to generate the fixup for the symbol and offset. */ + if (n == 0) + { + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, 1, + BFD_RELOC_16_PCREL); + fragp->fr_fix += 4; + return; + } + + /* Replace the cbranch at fr_fix with one that has the opposite condition + in order to jump around the block of instructions we'll be adding. */ + if (IS_CBRANCH (subtype)) + { + unsigned int br_opcode; + int nbytes; + + /* Account for the nextpc and jmp in the pc-relative case, or the two + load instructions and jump in the absolute case. */ + if (nios2_as_options.relax == relax_section) + nbytes = (n + 2) * 4; + else + nbytes = 12; + + br_opcode = md_chars_to_number (buffer, 4); + switch (br_opcode & OP_MASK_OP) + { + case OP_MATCH_BEQ: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BNE; + break; + case OP_MATCH_BNE: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BEQ ; + break; + case OP_MATCH_BGE: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BLT ; + break; + case OP_MATCH_BGEU: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BLTU ; + break; + case OP_MATCH_BLT: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BGE ; + break; + case OP_MATCH_BLTU: + br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BGEU ; + break; + default: + as_bad_where (fragp->fr_file, fragp->fr_line, + _("expecting conditional branch for relaxation\n")); + abort (); + } + + br_opcode = br_opcode | (nbytes << OP_SH_IMM16); + md_number_to_chars (buffer, br_opcode, 4); + fragp->fr_fix += 4; + buffer += 4; + } + + /* Load at for the PC-relative case. */ + if (nios2_as_options.relax == relax_section) + { + /* Insert the nextpc instruction. */ + md_number_to_chars (buffer, + OP_MATCH_NEXTPC | (AT_REGNUM << OP_SH_RRD), 4); + fragp->fr_fix += 4; + buffer += 4; + + /* We need to know whether the offset is positive or negative. */ + target += S_GET_VALUE (symbolp); + offset = target - fragp->fr_address - fragp->fr_fix; + if (offset > 0) + addend = 32767; + else + addend = -32768; + addend_mask = (((unsigned int)addend) & 0xffff) << OP_SH_IMM16; + + /* Insert n-1 addi instructions. */ + addi_mask = (OP_MATCH_ADDI + | (AT_REGNUM << OP_SH_IRD) + | (AT_REGNUM << OP_SH_IRS)); + for (i = 0; i < n - 1; i ++) + { + md_number_to_chars (buffer, addi_mask | addend_mask, 4); + fragp->fr_fix += 4; + buffer += 4; + } + + /* Insert the last addi instruction to hold the remainder. */ + remainder = offset - addend * (n - 1); + gas_assert (remainder >= -32768 && remainder <= 32767); + addend_mask = (((unsigned int)remainder) & 0xffff) << OP_SH_IMM16; + md_number_to_chars (buffer, addi_mask | addend_mask, 4); + fragp->fr_fix += 4; + buffer += 4; + } + + /* Load at for the absolute case. */ + else + { + md_number_to_chars (buffer, OP_MATCH_ORHI | 0x00400000, 4); + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, + 0, BFD_RELOC_NIOS2_HI16); + fragp->fr_fix += 4; + buffer += 4; + md_number_to_chars (buffer, OP_MATCH_ORI | 0x08400000, 4); + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, + 0, BFD_RELOC_NIOS2_LO16); + fragp->fr_fix += 4; + buffer += 4; + } + + /* Insert the jmp instruction. */ + md_number_to_chars (buffer, OP_MATCH_JMP | (AT_REGNUM << OP_SH_RRS), 4); + fragp->fr_fix += 4; + buffer += 4; +} + + +/** Fixups and overflow checking. */ + +/* Check a fixup for overflow. */ +static bfd_boolean +nios2_check_overflow (valueT fixup, reloc_howto_type *howto) +{ + /* Apply the rightshift before checking for overflow. */ + fixup = ((signed)fixup) >> howto->rightshift; + + /* Check for overflow - return TRUE if overflow, FALSE if not. */ + switch (howto->complain_on_overflow) + { + case complain_overflow_dont: + break; + case complain_overflow_bitfield: + if ((fixup >> howto->bitsize) != 0 + && ((signed) fixup >> howto->bitsize) != -1) + return TRUE; + break; + case complain_overflow_signed: + if ((fixup & 0x80000000) > 0) + { + /* Check for negative overflow. */ + if ((signed) fixup < ((signed) 0x80000000 >> howto->bitsize)) + return TRUE; + } + else + { + /* Check for positive overflow. */ + if (fixup >= ((unsigned) 1 << (howto->bitsize - 1))) + return TRUE; + } + break; + case complain_overflow_unsigned: + if ((fixup >> howto->bitsize) != 0) + return TRUE; + break; + default: + as_bad (_("error checking for overflow - broken assembler")); + break; + } + return FALSE; +} + +/* Emit diagnostic for fixup overflow. */ +static void +nios2_diagnose_overflow (valueT fixup, reloc_howto_type *howto, + fixS *fixP, valueT value) +{ + if (fixP->fx_r_type == BFD_RELOC_8 + || fixP->fx_r_type == BFD_RELOC_16 + || fixP->fx_r_type == BFD_RELOC_32) + /* These relocs are against data, not instructions. */ + as_bad_where (fixP->fx_file, fixP->fx_line, + _("immediate value 0x%x truncated to 0x%x"), + (unsigned int) fixup, + (unsigned int) (~(~(valueT) 0 << howto->bitsize) & fixup)); + else + { + /* What opcode is the instruction? This will determine + whether we check for overflow in immediate values + and what error message we get. */ + const struct nios2_opcode *opcode; + enum overflow_type overflow_msg_type; + unsigned int range_min; + unsigned int range_max; + unsigned int address; + gas_assert (fixP->fx_size == 4); + opcode = nios2_find_opcode_hash (value); + gas_assert (opcode); + overflow_msg_type = opcode->overflow_msg; + switch (overflow_msg_type) + { + case call_target_overflow: + range_min + = ((fixP->fx_frag->fr_address + fixP->fx_where) & 0xf0000000); + range_max = range_min + 0x0fffffff; + address = fixup | range_min; + + as_bad_where (fixP->fx_file, fixP->fx_line, + _("call target address 0x%08x out of range 0x%08x to 0x%08x"), + address, range_min, range_max); + break; + case branch_target_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("branch offset %d out of range %d to %d"), + (int)fixup, -32768, 32767); + break; + case address_offset_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("%s offset %d out of range %d to %d"), + opcode->name, (int)fixup, -32768, 32767); + break; + case signed_immed16_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("immediate value %d out of range %d to %d"), + (int)fixup, -32768, 32767); + break; + case unsigned_immed16_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("immediate value %u out of range %u to %u"), + (unsigned int)fixup, 0, 65535); + break; + case unsigned_immed5_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("immediate value %u out of range %u to %u"), + (unsigned int)fixup, 0, 31); + break; + case custom_opcode_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("custom instruction opcode %u out of range %u to %u"), + (unsigned int)fixup, 0, 255); + break; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("overflow in immediate argument")); + break; + } + } +} + +/* Apply a fixup to the object file. */ +void +md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +{ + /* Assert that the fixup is one we can handle. */ + gas_assert (fixP != NULL && valP != NULL + && (fixP->fx_r_type == BFD_RELOC_8 + || fixP->fx_r_type == BFD_RELOC_16 + || fixP->fx_r_type == BFD_RELOC_32 + || fixP->fx_r_type == BFD_RELOC_64 + || fixP->fx_r_type == BFD_RELOC_NIOS2_S16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_U16 + || fixP->fx_r_type == BFD_RELOC_16_PCREL + || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26 + || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5 + || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX + || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6 + || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM8 + || fixP->fx_r_type == BFD_RELOC_NIOS2_HI16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_LO16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_HIADJ16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_GPREL + || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixP->fx_r_type == BFD_RELOC_NIOS2_UJMP + || fixP->fx_r_type == BFD_RELOC_NIOS2_CJMP + || fixP->fx_r_type == BFD_RELOC_NIOS2_CALLR + || fixP->fx_r_type == BFD_RELOC_NIOS2_ALIGN + || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO + || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16 + || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF + || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL + /* Add other relocs here as we generate them. */ + )); + + if (fixP->fx_r_type == BFD_RELOC_64) + { + /* We may reach here due to .8byte directives, but we never output + BFD_RELOC_64; it must be resolved. */ + if (fixP->fx_addsy != NULL) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("cannot create 64-bit relocation")); + else + { + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + *valP, 8); + fixP->fx_done = 1; + } + return; + } + + /* The value passed in valP can be the value of a fully + resolved expression, or it can be the value of a partially + resolved expression. In the former case, both fixP->fx_addsy + and fixP->fx_subsy are NULL, and fixP->fx_offset == *valP, and + we can fix up the instruction that fixP relates to. + In the latter case, one or both of fixP->fx_addsy and + fixP->fx_subsy are not NULL, and fixP->fx_offset may or may not + equal *valP. We don't need to check for fixP->fx_subsy being null + because the generic part of the assembler generates an error if + it is not an absolute symbol. */ + if (fixP->fx_addsy != NULL) + /* Partially resolved expression. */ + { + fixP->fx_addnumber = fixP->fx_offset; + fixP->fx_done = 0; + + switch (fixP->fx_r_type) + { + case BFD_RELOC_NIOS2_TLS_GD16: + case BFD_RELOC_NIOS2_TLS_LDM16: + case BFD_RELOC_NIOS2_TLS_LDO16: + case BFD_RELOC_NIOS2_TLS_IE16: + case BFD_RELOC_NIOS2_TLS_LE16: + case BFD_RELOC_NIOS2_TLS_DTPMOD: + case BFD_RELOC_NIOS2_TLS_DTPREL: + case BFD_RELOC_NIOS2_TLS_TPREL: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + default: + break; + } + } + else + /* Fully resolved fixup. */ + { + reloc_howto_type *howto + = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + + if (howto == NULL) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("relocation is not supported")); + else + { + valueT fixup = *valP; + valueT value; + char *buf; + + /* If this is a pc-relative relocation, we need to + subtract the current offset within the object file + FIXME : for some reason fixP->fx_pcrel isn't 1 when it should be + so I'm using the howto structure instead to determine this. */ + if (howto->pc_relative == 1) + fixup = fixup - (fixP->fx_frag->fr_address + fixP->fx_where + 4); + + /* Get the instruction or data to be fixed up. */ + buf = fixP->fx_frag->fr_literal + fixP->fx_where; + value = md_chars_to_number (buf, fixP->fx_size); + + /* Check for overflow, emitting a diagnostic if necessary. */ + if (nios2_check_overflow (fixup, howto)) + nios2_diagnose_overflow (fixup, howto, fixP, value); + + /* Apply the right shift. */ + fixup = ((signed)fixup) >> howto->rightshift; + + /* Truncate the fixup to right size. */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_NIOS2_HI16: + fixup = (fixup >> 16) & 0xFFFF; + break; + case BFD_RELOC_NIOS2_LO16: + fixup = fixup & 0xFFFF; + break; + case BFD_RELOC_NIOS2_HIADJ16: + fixup = ((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01); + break; + default: + { + int n = sizeof (fixup) * 8 - howto->bitsize; + fixup = (fixup << n) >> n; + break; + } + } + + /* Fix up the instruction. */ + value = (value & ~howto->dst_mask) | (fixup << howto->bitpos); + md_number_to_chars (buf, value, fixP->fx_size); + } + + fixP->fx_done = 1; + } + + if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT) + { + fixP->fx_done = 0; + if (fixP->fx_addsy + && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy)) + S_SET_WEAK (fixP->fx_addsy); + } + else if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + fixP->fx_done = 0; +} + + + +/** Instruction parsing support. */ + +/* Special relocation directive strings. */ + +struct nios2_special_relocS +{ + const char *string; + bfd_reloc_code_real_type reloc_type; +}; + +struct nios2_special_relocS nios2_special_reloc[] = { + {"%hiadj", BFD_RELOC_NIOS2_HIADJ16}, + {"%hi", BFD_RELOC_NIOS2_HI16}, + {"%lo", BFD_RELOC_NIOS2_LO16}, + {"%gprel", BFD_RELOC_NIOS2_GPREL}, + {"%call", BFD_RELOC_NIOS2_CALL16}, + {"%gotoff_lo", BFD_RELOC_NIOS2_GOTOFF_LO}, + {"%gotoff_hiadj", BFD_RELOC_NIOS2_GOTOFF_HA}, + {"%tls_gd", BFD_RELOC_NIOS2_TLS_GD16}, + {"%tls_ldm", BFD_RELOC_NIOS2_TLS_LDM16}, + {"%tls_ldo", BFD_RELOC_NIOS2_TLS_LDO16}, + {"%tls_ie", BFD_RELOC_NIOS2_TLS_IE16}, + {"%tls_le", BFD_RELOC_NIOS2_TLS_LE16}, + {"%gotoff", BFD_RELOC_NIOS2_GOTOFF}, + {"%got", BFD_RELOC_NIOS2_GOT16} +}; + +#define NIOS2_NUM_SPECIAL_RELOCS \ + (sizeof(nios2_special_reloc)/sizeof(nios2_special_reloc[0])) +const int nios2_num_special_relocs = NIOS2_NUM_SPECIAL_RELOCS; + +/* Creates a new nios2_insn_relocS and returns a pointer to it. */ +static nios2_insn_relocS * +nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel) +{ + nios2_insn_relocS *retval; + retval = (nios2_insn_relocS *) malloc (sizeof (nios2_insn_relocS)); + if (retval == NULL) + { + as_bad (_("can't create relocation")); + abort (); + } + + /* Fill out the fields with default values. */ + retval->reloc_next = NULL; + retval->reloc_type = reloc_type; + retval->reloc_pcrel = pcrel; + return retval; +} + +/* Frees up memory previously allocated by nios2_insn_reloc_new(). */ +/* FIXME: this is never called; memory leak? */ +#if 0 +static void +nios2_insn_reloc_destroy (nios2_insn_relocS *reloc) +{ + gas_assert (reloc != NULL); + free (reloc); +} +#endif + +/* The various nios2_assemble_* functions call this + function to generate an expression from a string representing an expression. + It then tries to evaluate the expression, and if it can, returns its value. + If not, it creates a new nios2_insn_relocS and stores the expression and + reloc_type for future use. */ +static unsigned long +nios2_assemble_expression (const char *exprstr, + nios2_insn_infoS *insn, + nios2_insn_relocS *prev_reloc, + bfd_reloc_code_real_type reloc_type, + unsigned int pcrel) +{ + nios2_insn_relocS *reloc; + char *saved_line_ptr; + unsigned short value; + int i; + + gas_assert (exprstr != NULL); + gas_assert (insn != NULL); + + /* Check for relocation operators. + Change the relocation type and advance the ptr to the start of + the expression proper. */ + for (i = 0; i < nios2_num_special_relocs; i++) + if (strstr (exprstr, nios2_special_reloc[i].string) != NULL) + { + reloc_type = nios2_special_reloc[i].reloc_type; + exprstr += strlen (nios2_special_reloc[i].string) + 1; + + /* %lo and %hiadj have different meanings for PC-relative + expressions. */ + if (pcrel) + { + if (reloc_type == BFD_RELOC_NIOS2_LO16) + reloc_type = BFD_RELOC_NIOS2_PCREL_LO; + if (reloc_type == BFD_RELOC_NIOS2_HIADJ16) + reloc_type = BFD_RELOC_NIOS2_PCREL_HA; + } + + break; + } + + /* We potentially have a relocation. */ + reloc = nios2_insn_reloc_new (reloc_type, pcrel); + if (prev_reloc != NULL) + prev_reloc->reloc_next = reloc; + else + insn->insn_reloc = reloc; + + /* Parse the expression string. */ + saved_line_ptr = input_line_pointer; + input_line_pointer = (char *) exprstr; + expression (&reloc->reloc_expression); + input_line_pointer = saved_line_ptr; + + /* This is redundant as the fixup will put this into + the instruction, but it is included here so that + self-test mode (-r) works. */ + value = 0; + if (nios2_mode == NIOS2_MODE_TEST + && reloc->reloc_expression.X_op == O_constant) + value = reloc->reloc_expression.X_add_number; + + return (unsigned long) value; +} + +/* Argument assemble functions. + All take an instruction argument string, and a pointer + to an instruction opcode. Upon return the insn_opcode + has the relevant fields filled in to represent the arg + string. The return value is NULL if successful, or + an error message if an error was detected. + + The naming conventions for these functions match the args template + in the nios2_opcode structure, as documented in include/opcode/nios2.h. + For example, nios2_assemble_args_dst is used for instructions with + "d,s,t" args. + See nios2_arg_info_structs below for the exact correspondence. */ + +static void +nios2_assemble_args_dst (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]); + struct nios2_reg *src2 = nios2_reg_lookup (insn_info->insn_tokens[3]); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + if (src2 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + } +} + +static void +nios2_assemble_args_tsi (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]); + unsigned int src2 + = nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_tsu (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]); + unsigned int src2 + = nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_U16, + 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_sto (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]); + unsigned int src2 + = nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_16_PCREL, + 1); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_o (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL) + { + unsigned long immed + = nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, BFD_RELOC_16_PCREL, + 1); + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_is (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + struct nios2_reg *addr_src = nios2_reg_lookup (insn_info->insn_tokens[2]); + unsigned long immed + = nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + + if (addr_src == NULL) + as_bad (_("unknown base register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_m (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL) + { + unsigned long immed + = nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_CALL26, 0); + + SET_INSN_FIELD (IMM26, insn_info->insn_code, immed); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); + SET_INSN_FIELD (IMM26, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_s (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL) + { + struct nios2_reg *src = nios2_reg_lookup (insn_info->insn_tokens[1]); + if (src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); + } +} + +static void +nios2_assemble_args_tis (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *addr_src = nios2_reg_lookup (insn_info->insn_tokens[3]); + unsigned long immed + = nios2_assemble_expression (insn_info->insn_tokens[2], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + if (addr_src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, dst->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_dc (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + struct nios2_reg *ctl = nios2_reg_lookup (insn_info->insn_tokens[2]); + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + + if (ctl == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]); + } +} + +static void +nios2_assemble_args_cs (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + struct nios2_reg *ctl = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src = nios2_reg_lookup (insn_info->insn_tokens[2]); + + if (ctl == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else if (ctl->index == 4) + as_bad (_("ipending control register (ctl4) is read-only\n")); + else + SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index); + + if (src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]); + } +} + +static void +nios2_assemble_args_ldst (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL + && insn_info->insn_tokens[4] != NULL) + { + unsigned long custom_n + = nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM8, 0); + + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[2]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[3]); + struct nios2_reg *src2 = nios2_reg_lookup (insn_info->insn_tokens[4]); + + SET_INSN_FIELD (CUSTOM_N, insn_info->insn_code, custom_n); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + if (src2 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[4]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index); + + /* Set or clear the bits to indicate whether coprocessor registers are + used. */ + if (nios2_coproc_reg (insn_info->insn_tokens[2])) + SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 1); + + if (nios2_coproc_reg (insn_info->insn_tokens[3])) + SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 1); + + if (nios2_coproc_reg (insn_info->insn_tokens[4])) + SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 1); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[5]); + } +} + +static void +nios2_assemble_args_none (nios2_insn_infoS *insn_info ATTRIBUTE_UNUSED) +{ + /* Nothing to do. */ +} + +static void +nios2_assemble_args_dsj (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL + && insn_info->insn_tokens[2] != NULL + && insn_info->insn_tokens[3] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]); + + /* A 5-bit constant expression. */ + unsigned int src2 = + nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM5, 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM5, insn_info->insn_code, src2); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]); + SET_INSN_FIELD (IMM5, insn_info->insn_code, 0); + } +} + +static void +nios2_assemble_args_d (nios2_insn_infoS *insn_info) +{ + if (insn_info->insn_tokens[1] != NULL) + { + struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); + } +} + +static void +nios2_assemble_args_b (nios2_insn_infoS *insn_info) +{ + unsigned int imm5 = 0; + + if (insn_info->insn_tokens[1] != NULL) + { + /* A 5-bit constant expression. */ + imm5 = nios2_assemble_expression (insn_info->insn_tokens[1], + insn_info, insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM5, 0); + SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5); + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); + } + + SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5); + + nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); +} + +/* This table associates pointers to functions that parse the arguments to an + instruction and fill in the relevant fields of the instruction. */ +const nios2_arg_infoS nios2_arg_info_structs[] = { + /* args, assemble_args_func */ + {"d,s,t", nios2_assemble_args_dst}, + {"d,s,t,E", nios2_assemble_args_dst}, + {"t,s,i", nios2_assemble_args_tsi}, + {"t,s,i,E", nios2_assemble_args_tsi}, + {"t,s,u", nios2_assemble_args_tsu}, + {"t,s,u,E", nios2_assemble_args_tsu}, + {"s,t,o", nios2_assemble_args_sto}, + {"s,t,o,E", nios2_assemble_args_sto}, + {"o", nios2_assemble_args_o}, + {"o,E", nios2_assemble_args_o}, + {"s", nios2_assemble_args_s}, + {"s,E", nios2_assemble_args_s}, + {"", nios2_assemble_args_none}, + {"E", nios2_assemble_args_none}, + {"i(s)", nios2_assemble_args_is}, + {"i(s)E", nios2_assemble_args_is}, + {"m", nios2_assemble_args_m}, + {"m,E", nios2_assemble_args_m}, + {"t,i(s)", nios2_assemble_args_tis}, + {"t,i(s)E", nios2_assemble_args_tis}, + {"d,c", nios2_assemble_args_dc}, + {"d,c,E", nios2_assemble_args_dc}, + {"c,s", nios2_assemble_args_cs}, + {"c,s,E", nios2_assemble_args_cs}, + {"l,d,s,t", nios2_assemble_args_ldst}, + {"l,d,s,t,E", nios2_assemble_args_ldst}, + {"d,s,j", nios2_assemble_args_dsj}, + {"d,s,j,E", nios2_assemble_args_dsj}, + {"d", nios2_assemble_args_d}, + {"d,E", nios2_assemble_args_d}, + {"b", nios2_assemble_args_b}, + {"b,E", nios2_assemble_args_b} +}; + +#define NIOS2_NUM_ARGS \ + ((sizeof(nios2_arg_info_structs)/sizeof(nios2_arg_info_structs[0]))) +const int nios2_num_arg_info_structs = NIOS2_NUM_ARGS; + +/* The function consume_arg takes a pointer into a string + of instruction tokens (args) and a pointer into a string + representing the expected sequence of tokens and separators. + It checks whether the first argument in argstr is of the + expected type, throwing an error if it is not, and returns + the pointer argstr. */ +static char * +nios2_consume_arg (nios2_insn_infoS *insn, char *argstr, const char *parsestr) +{ + char *temp; + int regno = -1; + + switch (*parsestr) + { + case 'c': + if (!nios2_control_register_arg_p (argstr)) + as_bad (_("expecting control register")); + break; + case 'd': + case 's': + case 't': + + /* We check to make sure we don't have a control register. */ + if (nios2_control_register_arg_p (argstr)) + as_bad (_("illegal use of control register")); + + /* And whether coprocessor registers are valid here. */ + if (nios2_coproc_reg (argstr) + && insn->insn_nios2_opcode->match != OP_MATCH_CUSTOM) + as_bad (_("illegal use of coprocessor register\n")); + + /* Extract a register number if the register is of the + form r[0-9]+, if it is a normal register, set + regno to its number (0-31), else set regno to -1. */ + if (argstr[0] == 'r' && ISDIGIT (argstr[1])) + { + char *p = argstr; + + ++p; + regno = 0; + do + { + regno *= 10; + regno += *p - '0'; + ++p; + } + while (ISDIGIT (*p)); + } + else + regno = -1; + + /* And whether we are using at. */ + if (!nios2_as_options.noat + && (regno == 1 || strprefix (argstr, "at"))) + as_warn (_("Register at (r1) can sometimes be corrupted by assembler " + "optimizations.\n" + "Use .set noat to turn off those optimizations (and this " + "warning).")); + + /* And whether we are using oci registers. */ + if (!nios2_as_options.nobreak + && (regno == 25 || strprefix (argstr, "bt"))) + as_warn (_("The debugger will corrupt bt (r25). If you don't need to " + "debug this\n" + "code then use .set nobreak to turn off this warning.")); + + if (!nios2_as_options.nobreak + && (regno == 30 || strprefix (argstr, "ba"))) + as_warn (_("The debugger will corrupt ba (r30). If you don't need to " + "debug this\n" + "code then use .set nobreak to turn off this warning.")); + break; + case 'i': + case 'u': + if (*argstr == '%') + { + if (nios2_special_relocation_p (argstr)) + { + /* We zap the parentheses because we don't want them confused + with separators. */ + temp = strchr (argstr, '('); + if (temp != NULL) + *temp = ' '; + temp = strchr (argstr, ')'); + if (temp != NULL) + *temp = ' '; + } + else + as_bad (_("badly formed expression near %s"), argstr); + } + break; + case 'm': + case 'j': + case 'k': + case 'l': + case 'b': + /* We can't have %hi, %lo or %hiadj here. */ + if (*argstr == '%') + as_bad (_("badly formed expression near %s"), argstr); + break; + default: + break; + } + + return argstr; +} + +/* The function consume_separator takes a pointer into a string + of instruction tokens (args) and a pointer into a string representing + the expected sequence of tokens and separators. It finds the first + instance of the character pointed to by separator in argstr, and + returns a pointer to the next element of argstr, which is the + following token in the sequence. */ +static char * +nios2_consume_separator (char *argstr, const char *separator) +{ + char *p; + + /* If we have a opcode reg, expr(reg) type instruction, and + * we are separating the expr from the (reg), we find the last + * (, just in case the expression has parentheses. */ + + if (*separator == '(') + p = strrchr (argstr, *separator); + else + p = strchr (argstr, *separator); + + if (p != NULL) + *p++ = 0; + else + as_bad (_("expecting %c near %s"), *separator, argstr); + return p; +} + + +/* The principal argument parsing function which takes a string argstr + representing the instruction arguments for insn, and extracts the argument + tokens matching parsestr into parsed_args. */ +static void +nios2_parse_args (nios2_insn_infoS *insn, char *argstr, + const char *parsestr, char **parsed_args) +{ + char *p; + char *end = NULL; + int i; + p = argstr; + i = 0; + bfd_boolean terminate = FALSE; + + /* This rest of this function is it too fragile and it mostly works, + therefore special case this one. */ + if (*parsestr == 0 && argstr != 0) + { + as_bad (_("too many arguments")); + parsed_args[0] = NULL; + return; + } + + while (p != NULL && !terminate && i < NIOS2_MAX_INSN_TOKENS) + { + parsed_args[i] = nios2_consume_arg (insn, p, parsestr); + ++parsestr; + if (*parsestr != '\0') + { + p = nios2_consume_separator (p, parsestr); + ++parsestr; + } + else + { + /* Check that the argument string has no trailing arguments. */ + /* If we've got a %lo etc relocation, we've zapped the parens with + spaces. */ + if (nios2_special_relocation_p (p)) + end = strpbrk (p, ","); + else + end = strpbrk (p, " ,"); + + if (end != NULL) + as_bad (_("too many arguments")); + } + + if (*parsestr == '\0' || (p != NULL && *p == '\0')) + terminate = TRUE; + ++i; + } + + parsed_args[i] = NULL; + + if (*parsestr != '\0' && insn->insn_nios2_opcode->match != OP_MATCH_BREAK) + as_bad (_("missing argument")); +} + + + +/** Support for pseudo-op parsing. These are macro-like opcodes that + expand into real insns by suitable fiddling with the operands. */ + +/* Append the string modifier to the string contained in the argument at + parsed_args[ndx]. */ +static void +nios2_modify_arg (char **parsed_args, const char *modifier, + int unused ATTRIBUTE_UNUSED, int ndx) +{ + char *tmp = parsed_args[ndx]; + + parsed_args[ndx] + = (char *) malloc (strlen (parsed_args[ndx]) + strlen (modifier) + 1); + strcpy (parsed_args[ndx], tmp); + strcat (parsed_args[ndx], modifier); +} + +/* Modify parsed_args[ndx] by negating that argument. */ +static void +nios2_negate_arg (char **parsed_args, const char *modifier ATTRIBUTE_UNUSED, + int unused ATTRIBUTE_UNUSED, int ndx) +{ + char *tmp = parsed_args[ndx]; + + parsed_args[ndx] + = (char *) malloc (strlen ("~(") + strlen (parsed_args[ndx]) + + strlen (")+1") + 1); + + strcpy (parsed_args[ndx], "~("); + strcat (parsed_args[ndx], tmp); + strcat (parsed_args[ndx], ")+1"); +} + +/* The function nios2_swap_args swaps the pointers at indices index_1 and + index_2 in the array parsed_args[] - this is used for operand swapping + for comparison operations. */ +static void +nios2_swap_args (char **parsed_args, const char *unused ATTRIBUTE_UNUSED, + int index_1, int index_2) +{ + char *tmp; + gas_assert (index_1 < NIOS2_MAX_INSN_TOKENS + && index_2 < NIOS2_MAX_INSN_TOKENS); + tmp = parsed_args[index_1]; + parsed_args[index_1] = parsed_args[index_2]; + parsed_args[index_2] = tmp; +} + +/* This function appends the string appnd to the array of strings in + parsed_args num times starting at index start in the array. */ +static void +nios2_append_arg (char **parsed_args, const char *appnd, int num, + int start) +{ + int i, count; + char *tmp; + + gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS); + + if (nios2_mode == NIOS2_MODE_TEST) + tmp = parsed_args[start]; + else + tmp = NULL; + + for (i = start, count = num; count > 0; ++i, --count) + parsed_args[i] = (char *) appnd; + + gas_assert (i == (start + num)); + parsed_args[i] = tmp; + parsed_args[i + 1] = NULL; +} + +/* This function inserts the string insert num times in the array + parsed_args, starting at the index start. */ +static void +nios2_insert_arg (char **parsed_args, const char *insert, int num, + int start) +{ + int i, count; + + gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS); + + /* Move the existing arguments up to create space. */ + for (i = NIOS2_MAX_INSN_TOKENS; i - num >= start; --i) + parsed_args[i] = parsed_args[i - num]; + + for (i = start, count = num; count > 0; ++i, --count) + parsed_args[i] = (char *) insert; +} + +/* Cleanup function to free malloc'ed arg strings. */ +static void +nios2_free_arg (char **parsed_args, int num ATTRIBUTE_UNUSED, int start) +{ + if (parsed_args[start]) + { + free (parsed_args[start]); + parsed_args[start] = NULL; + } +} + +/* This function swaps the pseudo-op for a real op. */ +static nios2_ps_insn_infoS* +nios2_translate_pseudo_insn (nios2_insn_infoS *insn) +{ + + nios2_ps_insn_infoS *ps_insn; + + /* Find which real insn the pseudo-op transates to and + switch the insn_info ptr to point to it. */ + ps_insn = nios2_ps_lookup (insn->insn_nios2_opcode->name); + + if (ps_insn != NULL) + { + insn->insn_nios2_opcode = nios2_opcode_lookup (ps_insn->insn); + insn->insn_tokens[0] = insn->insn_nios2_opcode->name; + /* Modify the args so they work with the real insn. */ + ps_insn->arg_modifer_func ((char **) insn->insn_tokens, + ps_insn->arg_modifier, ps_insn->num, + ps_insn->index); + } + else + /* we cannot recover from this. */ + as_fatal (_("unrecognized pseudo-instruction %s"), + ps_insn->pseudo_insn); + return ps_insn; +} + +/* Invoke the cleanup handler for pseudo-insn ps_insn on insn. */ +static void +nios2_cleanup_pseudo_insn (nios2_insn_infoS *insn, + nios2_ps_insn_infoS *ps_insn) +{ + if (ps_insn->arg_cleanup_func) + (ps_insn->arg_cleanup_func) ((char **) insn->insn_tokens, + ps_insn->num, ps_insn->index); +} + +const nios2_ps_insn_infoS nios2_ps_insn_info_structs[] = { + /* pseudo-op, real-op, arg, arg_modifier_func, num, index, arg_cleanup_func */ + {"mov", "add", nios2_append_arg, "zero", 1, 3, NULL}, + {"movi", "addi", nios2_insert_arg, "zero", 1, 2, NULL}, + {"movhi", "orhi", nios2_insert_arg, "zero", 1, 2, NULL}, + {"movui", "ori", nios2_insert_arg, "zero", 1, 2, NULL}, + {"movia", "orhi", nios2_insert_arg, "zero", 1, 2, NULL}, + {"nop", "add", nios2_append_arg, "zero", 3, 1, NULL}, + {"bgt", "blt", nios2_swap_args, "", 1, 2, NULL}, + {"bgtu", "bltu", nios2_swap_args, "", 1, 2, NULL}, + {"ble", "bge", nios2_swap_args, "", 1, 2, NULL}, + {"bleu", "bgeu", nios2_swap_args, "", 1, 2, NULL}, + {"cmpgt", "cmplt", nios2_swap_args, "", 2, 3, NULL}, + {"cmpgtu", "cmpltu", nios2_swap_args, "", 2, 3, NULL}, + {"cmple", "cmpge", nios2_swap_args, "", 2, 3, NULL}, + {"cmpleu", "cmpgeu", nios2_swap_args, "", 2, 3, NULL}, + {"cmpgti", "cmpgei", nios2_modify_arg, "+1", 0, 3, nios2_free_arg}, + {"cmpgtui", "cmpgeui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg}, + {"cmplei", "cmplti", nios2_modify_arg, "+1", 0, 3, nios2_free_arg}, + {"cmpleui", "cmpltui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg}, + {"subi", "addi", nios2_negate_arg, "", 0, 3, nios2_free_arg} + /* Add further pseudo-ops here. */ +}; + +#define NIOS2_NUM_PSEUDO_INSNS \ + ((sizeof(nios2_ps_insn_info_structs)/ \ + sizeof(nios2_ps_insn_info_structs[0]))) +const int nios2_num_ps_insn_info_structs = NIOS2_NUM_PSEUDO_INSNS; + + +/** Assembler output support. */ + +static int +can_evaluate_expr (nios2_insn_infoS *insn) +{ + /* Remove this check for null and the invalid insn "ori r9, 1234" seg faults. */ + if (!insn->insn_reloc) + /* ??? Ideally we should do something other than as_fatal here as we can + continue to assemble. + However this function (actually the output_* functions) should not + have been called in the first place once an illegal instruction had + been encountered. */ + as_fatal (_("Invalid instruction encountered, cannot recover. No assembly attempted.")); + + if (insn->insn_reloc->reloc_expression.X_op == O_constant) + return 1; + + return 0; +} + +static int +get_expr_value (nios2_insn_infoS *insn) +{ + int value = 0; + + if (insn->insn_reloc->reloc_expression.X_op == O_constant) + value = insn->insn_reloc->reloc_expression.X_add_number; + return value; +} + +/* Output a normal instruction. */ +static void +output_insn (nios2_insn_infoS *insn) +{ + char *f; + nios2_insn_relocS *reloc; + + f = frag_more (4); + /* This allocates enough space for the instruction + and puts it in the current frag. */ + md_number_to_chars (f, insn->insn_code, 4); + /* Emit debug info. */ + dwarf2_emit_insn (4); + /* Create any fixups to be acted on later. */ + for (reloc = insn->insn_reloc; reloc != NULL; reloc = reloc->reloc_next) + fix_new_exp (frag_now, f - frag_now->fr_literal, 4, + &reloc->reloc_expression, reloc->reloc_pcrel, + reloc->reloc_type); +} + +/* Output an unconditional branch. */ +static void +output_ubranch (nios2_insn_infoS *insn) +{ + nios2_insn_relocS *reloc = insn->insn_reloc; + + /* If the reloc is NULL, there was an error assembling the branch. */ + if (reloc != NULL) + { + symbolS *symp = reloc->reloc_expression.X_add_symbol; + offsetT offset = reloc->reloc_expression.X_add_number; + char *f; + + /* Tag dwarf2 debug info to the address at the start of the insn. + We must do it before frag_var() below closes off the frag. */ + dwarf2_emit_insn (0); + + /* We create a machine dependent frag which can grow + to accommodate the largest possible instruction sequence + this may generate. */ + f = frag_var (rs_machine_dependent, + UBRANCH_MAX_SIZE, 4, UBRANCH_SUBTYPE (0), + symp, offset, NULL); + + md_number_to_chars (f, insn->insn_code, 4); + + /* We leave fixup generation to md_convert_frag. */ + } +} + +/* Output a conditional branch. */ +static void +output_cbranch (nios2_insn_infoS *insn) +{ + nios2_insn_relocS *reloc = insn->insn_reloc; + + /* If the reloc is NULL, there was an error assembling the branch. */ + if (reloc != NULL) + { + symbolS *symp = reloc->reloc_expression.X_add_symbol; + offsetT offset = reloc->reloc_expression.X_add_number; + char *f; + + /* Tag dwarf2 debug info to the address at the start of the insn. + We must do it before frag_var() below closes off the frag. */ + dwarf2_emit_insn (0); + + /* We create a machine dependent frag which can grow + to accommodate the largest possible instruction sequence + this may generate. */ + f = frag_var (rs_machine_dependent, + CBRANCH_MAX_SIZE, 4, CBRANCH_SUBTYPE (0), + symp, offset, NULL); + + md_number_to_chars (f, insn->insn_code, 4); + + /* We leave fixup generation to md_convert_frag. */ + } +} + +/* Output a call sequence. Since calls are not pc-relative for NIOS2, + but are page-relative, we cannot tell at any stage in assembly + whether a call will be out of range since a section may be linked + at any address. So if we are relaxing, we convert all call instructions + to long call sequences, and rely on the linker to relax them back to + short calls. */ +static void +output_call (nios2_insn_infoS *insn) +{ + /* This allocates enough space for the instruction + and puts it in the current frag. */ + char *f = frag_more (12); + nios2_insn_relocS *reloc = insn->insn_reloc; + + md_number_to_chars (f, OP_MATCH_ORHI | 0x00400000, 4); + dwarf2_emit_insn (4); + fix_new_exp (frag_now, f - frag_now->fr_literal, 4, + &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_HI16); + md_number_to_chars (f + 4, OP_MATCH_ORI | 0x08400000, 4); + dwarf2_emit_insn (4); + fix_new_exp (frag_now, f - frag_now->fr_literal + 4, 4, + &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_LO16); + md_number_to_chars (f + 8, OP_MATCH_CALLR | 0x08000000, 4); + dwarf2_emit_insn (4); +} + +/* Output an addi - will silently convert to + orhi if rA = r0 and (expr & 0xffff0000) == 0. */ +static void +output_addi (nios2_insn_infoS *insn) +{ + if (can_evaluate_expr (insn)) + { + int expr_val = get_expr_value (insn); + if (GET_INSN_FIELD (RRS, insn->insn_code) == 0 + && (expr_val & 0xffff) == 0 + && expr_val != 0) + { + /* We really want a movhi (orhi) here. */ + insn->insn_code = (insn->insn_code & ~OP_MATCH_ADDI) | OP_MATCH_ORHI; + insn->insn_reloc->reloc_expression.X_add_number = + (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff; + insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16; + } + } + + /* Output an instruction. */ + output_insn (insn); +} + +static void +output_andi (nios2_insn_infoS *insn) +{ + if (can_evaluate_expr (insn)) + { + int expr_val = get_expr_value (insn); + if (expr_val != 0 && (expr_val & 0xffff) == 0) + { + /* We really want a movhi (orhi) here. */ + insn->insn_code = (insn->insn_code & ~OP_MATCH_ANDI) | OP_MATCH_ANDHI; + insn->insn_reloc->reloc_expression.X_add_number = + (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff; + insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16; + } + } + + /* Output an instruction. */ + output_insn (insn); +} + +static void +output_ori (nios2_insn_infoS *insn) +{ + if (can_evaluate_expr (insn)) + { + int expr_val = get_expr_value (insn); + if (expr_val != 0 && (expr_val & 0xffff) == 0) + { + /* We really want a movhi (orhi) here. */ + insn->insn_code = (insn->insn_code & ~OP_MATCH_ORI) | OP_MATCH_ORHI; + insn->insn_reloc->reloc_expression.X_add_number = + (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff; + insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16; + } + } + + /* Output an instruction. */ + output_insn (insn); +} + +static void +output_xori (nios2_insn_infoS *insn) +{ + if (can_evaluate_expr (insn)) + { + int expr_val = get_expr_value (insn); + if (expr_val != 0 && (expr_val & 0xffff) == 0) + { + /* We really want a movhi (orhi) here. */ + insn->insn_code = (insn->insn_code & ~OP_MATCH_XORI) | OP_MATCH_XORHI; + insn->insn_reloc->reloc_expression.X_add_number = + (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff; + insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16; + } + } + + /* Output an instruction. */ + output_insn (insn); +} + + +/* Output a movhi/addi pair for the movia pseudo-op. */ +static void +output_movia (nios2_insn_infoS *insn) +{ + /* This allocates enough space for the instruction + and puts it in the current frag. */ + char *f = frag_more (8); + nios2_insn_relocS *reloc = insn->insn_reloc; + unsigned long reg_index = GET_INSN_FIELD (IRT, insn->insn_code); + + /* If the reloc is NULL, there was an error assembling the movia. */ + if (reloc != NULL) + { + md_number_to_chars (f, insn->insn_code, 4); + dwarf2_emit_insn (4); + md_number_to_chars (f + 4, + (OP_MATCH_ADDI | (reg_index << OP_SH_IRT) + | (reg_index << OP_SH_IRS)), + 4); + dwarf2_emit_insn (4); + fix_new (frag_now, f - frag_now->fr_literal, 4, + reloc->reloc_expression.X_add_symbol, + reloc->reloc_expression.X_add_number, 0, + BFD_RELOC_NIOS2_HIADJ16); + fix_new (frag_now, f + 4 - frag_now->fr_literal, 4, + reloc->reloc_expression.X_add_symbol, + reloc->reloc_expression.X_add_number, 0, BFD_RELOC_NIOS2_LO16); + } +} + + + +/** External interfaces. */ + +/* The following functions are called by machine-independent parts of + the assembler. */ +int +md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) +{ + switch (c) + { + case 'r': + /* Hidden option for self-test mode. */ + nios2_mode = NIOS2_MODE_TEST; + break; + case OPTION_RELAX_ALL: + nios2_as_options.relax = relax_all; + break; + case OPTION_NORELAX: + nios2_as_options.relax = relax_none; + break; + case OPTION_RELAX_SECTION: + nios2_as_options.relax = relax_section; + break; + case OPTION_EB: + target_big_endian = 1; + break; + case OPTION_EL: + target_big_endian = 0; + break; + default: + return 0; + break; + } + + return 1; +} + +/* Implement TARGET_FORMAT. We can choose to be big-endian or + little-endian at runtime based on a switch. */ +const char * +nios2_target_format (void) +{ + return target_big_endian ? "elf32-bignios2" : "elf32-littlenios2"; +} + +/* Machine-dependent usage message. */ +void +md_show_usage (FILE *stream) +{ + fprintf (stream, " NIOS2 options:\n" + " -relax-all replace all branch and call " + "instructions with jmp and callr sequences\n" + " -relax-section replace identified out of range " + "branches with jmp sequences (default)\n" + " -no-relax do not replace any branches or calls\n" + " -EB force big-endian byte ordering\n" + " -EL force little-endian byte ordering\n"); +} + +/* This function is called once, at assembler startup time. + It should set up all the tables, etc. that the MD part of the + assembler will need. */ +void +md_begin (void) +{ + int i; + const char *inserted; + + /* Create and fill a hashtable for the Nios II opcodes, registers and + arguments. */ + nios2_opcode_hash = hash_new (); + nios2_reg_hash = hash_new (); + nios2_arg_hash = hash_new (); + nios2_ps_hash = hash_new (); + + for (i = 0; i < NUMOPCODES; ++i) + { + inserted + = hash_insert (nios2_opcode_hash, nios2_opcodes[i].name, + (PTR) & nios2_opcodes[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_opcodes[i].name, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + for (i = 0; i < nios2_num_regs; ++i) + { + inserted + = hash_insert (nios2_reg_hash, nios2_regs[i].name, + (PTR) & nios2_regs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_regs[i].name, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + + } + + for (i = 0; i < nios2_num_arg_info_structs; ++i) + { + inserted + = hash_insert (nios2_arg_hash, nios2_arg_info_structs[i].args, + (PTR) & nios2_arg_info_structs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_arg_info_structs[i].args, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + for (i = 0; i < nios2_num_ps_insn_info_structs; ++i) + { + inserted + = hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn, + (PTR) & nios2_ps_insn_info_structs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_ps_insn_info_structs[i].pseudo_insn, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + /* Assembler option defaults. */ + nios2_as_options.noat = FALSE; + nios2_as_options.nobreak = FALSE; + + /* Debug information is incompatible with relaxation. */ + if (debug_type != DEBUG_UNSPECIFIED) + nios2_as_options.relax = relax_none; + + /* Initialize the alignment data. */ + nios2_current_align_seg = now_seg; + nios2_last_label = NULL; + nios2_current_align = 0; +} + + +/* Assembles a single line of Nios II assembly language. */ +void +md_assemble (char *op_str) +{ + char *argstr; + char *op_strdup = NULL; + nios2_arg_infoS *arg_info; + unsigned long saved_pinfo = 0; + nios2_insn_infoS thisinsn; + nios2_insn_infoS *insn = &thisinsn; + + /* Make sure we are aligned on a 4-byte boundary. */ + if (nios2_current_align < 2) + nios2_align (2, NULL, nios2_last_label); + else if (nios2_current_align > 2) + nios2_current_align = 2; + nios2_last_label = NULL; + + /* We don't want to clobber to op_str + because we want to be able to use it in messages. */ + op_strdup = strdup (op_str); + insn->insn_tokens[0] = strtok (op_strdup, " "); + argstr = strtok (NULL, ""); + + /* Assemble the opcode. */ + insn->insn_nios2_opcode = nios2_opcode_lookup (insn->insn_tokens[0]); + insn->insn_reloc = NULL; + + if (insn->insn_nios2_opcode != NULL) + { + nios2_ps_insn_infoS *ps_insn = NULL; + /* Set the opcode for the instruction. */ + insn->insn_code = insn->insn_nios2_opcode->match; + + /* Parse the arguments pointed to by argstr. */ + if (nios2_mode == NIOS2_MODE_ASSEMBLE) + nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args, + (char **) &insn->insn_tokens[1]); + else + nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args_test, + (char **) &insn->insn_tokens[1]); + + /* We need to preserve the MOVIA macro as this is clobbered by + translate_pseudo_insn. */ + if (insn->insn_nios2_opcode->pinfo == NIOS2_INSN_MACRO_MOVIA) + saved_pinfo = NIOS2_INSN_MACRO_MOVIA; + /* If the instruction is an pseudo-instruction, we want to replace it + with its real equivalent, and then continue. */ + if ((insn->insn_nios2_opcode->pinfo & NIOS2_INSN_MACRO) + == NIOS2_INSN_MACRO) + ps_insn = nios2_translate_pseudo_insn (insn); + + /* Find the assemble function, and call it. */ + arg_info = nios2_arg_lookup (insn->insn_nios2_opcode->args); + if (arg_info != NULL) + { + arg_info->assemble_args_func (insn); + + if (nios2_as_options.relax != relax_none + && !nios2_as_options.noat + && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH) + output_ubranch (insn); + else if (nios2_as_options.relax != relax_none + && !nios2_as_options.noat + && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH) + output_cbranch (insn); + else if (nios2_as_options.relax == relax_all + && !nios2_as_options.noat + && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL + && insn->insn_reloc + && insn->insn_reloc->reloc_type == BFD_RELOC_NIOS2_CALL26) + output_call (insn); + else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ANDI) + output_andi (insn); + else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ORI) + output_ori (insn); + else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_XORI) + output_xori (insn); + else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ADDI) + output_addi (insn); + else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA) + output_movia (insn); + else + output_insn (insn); + if (ps_insn) + nios2_cleanup_pseudo_insn (insn, ps_insn); + } + else + { + /* The assembler is broken. */ + fprintf (stderr, + _("internal error: %s is not a valid argument syntax\n"), + insn->insn_nios2_opcode->args); + /* Probably a memory allocation problem. Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + else + /* Unrecognised instruction - error. */ + as_bad (_("unrecognised instruction %s"), insn->insn_tokens[0]); + + /* Don't leak memory. */ + free (op_strdup); +} + +/* Round up section size. */ +valueT +md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT size) +{ + /* I think byte alignment is fine here. */ + return size; +} + +/* Implement TC_FORCE_RELOCATION. */ +int +nios2_force_relocation (fixS *fixp) +{ + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixp->fx_r_type == BFD_RELOC_NIOS2_ALIGN) + return 1; + + return generic_force_reloc (fixp); +} + +/* Implement tc_fix_adjustable. */ +int +nios2_fix_adjustable (fixS *fixp) +{ + if (fixp->fx_addsy == NULL) + return 1; + +#ifdef OBJ_ELF + /* Prevent all adjustments to global symbols. */ + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))) + return 0; +#endif + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; + + /* Preserve relocations against symbols with function type. */ + if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION) + return 0; + + /* Don't allow symbols to be discarded on GOT related relocs. */ + if (fixp->fx_r_type == BFD_RELOC_NIOS2_GOT16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO + || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16 + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPMOD + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL + || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_TPREL + || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF) + return 0; + + return 1; +} + +/* Implement tc_frob_symbol. This is called in adjust_reloc_syms; + it is used to remove *ABS* references from the symbol table. */ +int +nios2_frob_symbol (symbolS *symp) +{ + if ((OUTPUT_FLAVOR == bfd_target_elf_flavour + && symp == section_symbol (absolute_section)) + || !S_IS_DEFINED (symp)) + return 1; + else + return 0; +} + +/* The function tc_gen_reloc creates a relocation structure for the + fixup fixp, and returns a pointer to it. This structure is passed + to bfd_install_relocation so that it can be written to the object + file for linking. */ +arelent * +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) +{ + arelent *reloc = (arelent *) xmalloc (sizeof (arelent)); + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = fixp->fx_offset; /* fixp->fx_addnumber; */ + + if (fixp->fx_pcrel) + { + switch (fixp->fx_r_type) + { + case BFD_RELOC_16: + fixp->fx_r_type = BFD_RELOC_16_PCREL; + break; + case BFD_RELOC_NIOS2_LO16: + fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_LO; + break; + case BFD_RELOC_NIOS2_HIADJ16: + fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_HA; + break; + default: + break; + } + } + + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can't represent relocation type %s"), + bfd_get_reloc_code_name (fixp->fx_r_type)); + + /* Set howto to a garbage value so that we can keep going. */ + reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + gas_assert (reloc->howto != NULL); + } + return reloc; +} + +long +md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED) +{ + return 0; +} + +/* Called just before the assembler exits. */ +void +md_end () +{ + /* FIXME - not yet implemented */ +} + +/* Under ELF we need to default _GLOBAL_OFFSET_TABLE. + Otherwise we have no need to default values of symbols. */ +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +{ +#ifdef OBJ_ELF + if (name[0] == '_' && name[1] == 'G' + && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad ("GOT already in the symbol table"); + + GOT_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + } + + return GOT_symbol; + } +#endif + + return 0; +} + +/* Implement tc_frob_label. */ +void +nios2_frob_label (symbolS *lab) +{ + /* Emit dwarf information. */ + dwarf2_emit_label (lab); + + /* Update the label's address with the current output pointer. */ + symbol_set_frag (lab, frag_now); + S_SET_VALUE (lab, (valueT) frag_now_fix ()); + + /* Record this label for future adjustment after we find out what + kind of data it references, and the required alignment therewith. */ + nios2_last_label = lab; +} + +/* Implement md_cons_align. */ +void +nios2_cons_align (int size) +{ + int log_size = 0; + const char *pfill = NULL; + + while ((size >>= 1) != 0) + ++log_size; + + if (subseg_text_p (now_seg)) + pfill = (const char *) &nop; + else + pfill = NULL; + + if (nios2_auto_align_on) + nios2_align (log_size, pfill, NULL); + + nios2_last_label = NULL; +} + +/* Map 's' to SHF_NIOS2_GPREL. */ +/* This is from the Alpha code tc-alpha.c. */ +int +nios2_elf_section_letter (int letter, char **ptr_msg) +{ + if (letter == 's') + return SHF_NIOS2_GPREL; + + *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string"); + return -1; +} + +/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */ +/* This is from the Alpha code tc-alpha.c. */ +flagword +nios2_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED) +{ + if (attr & SHF_NIOS2_GPREL) + flags |= SEC_SMALL_DATA; + return flags; +} + +/* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) */ +static int nios2_tls_ldo_reloc; + +void +nios2_cons (expressionS *exp, int size) +{ + nios2_tls_ldo_reloc = 0; + + SKIP_WHITESPACE (); + if (input_line_pointer[0] == '%') + { + if (strprefix (input_line_pointer + 1, "tls_ldo")) + { + if (size != 4) + as_bad (_("Illegal operands: %%tls_ldo in %d-byte data field"), + size); + else + { + input_line_pointer += 8; + nios2_tls_ldo_reloc = 1; + } + } + if (nios2_tls_ldo_reloc) + { + SKIP_WHITESPACE (); + if (input_line_pointer[0] != '(') + as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()")); + else + { + int c; + char *end = ++input_line_pointer; + int npar = 0; + + for (c = *end; !is_end_of_line[c]; end++, c = *end) + if (c == '(') + npar++; + else if (c == ')') + { + if (!npar) + break; + npar--; + } + + if (c != ')') + as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()")); + else + { + *end = '\0'; + expression (exp); + *end = c; + if (input_line_pointer != end) + as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()")); + else + { + input_line_pointer++; + SKIP_WHITESPACE (); + c = *input_line_pointer; + if (! is_end_of_line[c] && c != ',') + as_bad (_("Illegal operands: garbage after %%tls_ldo()")); + } + } + } + } + } + if (!nios2_tls_ldo_reloc) + expression (exp); +} + +/* Implement TC_CONS_FIX_NEW. */ +void +nios2_cons_fix_new (fragS *frag, int where, unsigned int nbytes, + expressionS *exp) +{ + bfd_reloc_code_real_type r; + + r = (nbytes == 1 ? BFD_RELOC_8 + : (nbytes == 2 ? BFD_RELOC_16 + : (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64))); + + if (nios2_tls_ldo_reloc) + r = BFD_RELOC_NIOS2_TLS_DTPREL; + + fix_new_exp (frag, where, (int) nbytes, exp, 0, r); + nios2_tls_ldo_reloc = 0; +} + +/* Implement HANDLE_ALIGN. */ +void +nios2_handle_align (fragS *fragp) +{ + /* If we are expecting to relax in the linker, then we must output a + relocation to tell the linker we are aligning code. */ + if (nios2_as_options.relax == relax_all + && (fragp->fr_type == rs_align || fragp->fr_type == rs_align_code) + && fragp->fr_address + fragp->fr_fix > 0 + && fragp->fr_offset > 1 + && now_seg != bss_section) + fix_new (fragp, fragp->fr_fix, 0, &abs_symbol, fragp->fr_offset, 0, + BFD_RELOC_NIOS2_ALIGN); +} + +/* Implement tc_regname_to_dw2regnum, to convert REGNAME to a DWARF-2 + register number. */ +int +nios2_regname_to_dw2regnum (char *regname) +{ + struct nios2_reg *r = nios2_reg_lookup (regname); + if (r == NULL) + return -1; + return r->index; +} + +/* Implement tc_cfi_frame_initial_instructions, to initialize the DWARF-2 + unwind information for this procedure. */ +void +nios2_frame_initial_instructions (void) +{ + cfi_add_CFA_def_cfa (27, 0); +} diff --git a/gas/config/tc-nios2.h b/gas/config/tc-nios2.h new file mode 100644 index 0000000..9e69194 --- /dev/null +++ b/gas/config/tc-nios2.h @@ -0,0 +1,125 @@ +/* Definitions for Altera Nios II assembler. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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_NIOS2 +#define TC_NIOS2 + +/* If unspecified, default to little endian. We can explicitly specify + * a big-endian default by configuring with --target=nios2eb-elf. We + * can override the default with the -EB and -EL options. */ +#ifndef TARGET_BYTES_BIG_ENDIAN +#define TARGET_BYTES_BIG_ENDIAN 0 +#endif + +/* Words are big enough to hold addresses. */ +#define WORKING_DOT_WORD 1 + +#ifdef OBJ_ELF +extern const char *nios2_target_format (void); +#define TARGET_FORMAT nios2_target_format () +#define TARGET_ARCH bfd_arch_nios2 +#endif + +/* A NIOS2 instruction consists of tokens and separator characters + the tokens are things like the instruction name (add, or jmp etc), + the register indices ($5, $7 etc), and constant expressions. The + separator characters are commas, brackets and space. + The instruction name is always separated from other tokens by a space + The maximum number of tokens in an instruction is 5 (the instruction name, + 3 arguments, and a 4th string representing the expected instructin opcode + after assembly. The latter is only used when the assemble is running in + self test mode, otherwise its presence will generate an error. */ +#define NIOS2_MAX_INSN_TOKENS 6 + +/* There are no machine-specific operands so we #define this to nothing. */ +#define md_operand(x) + +/* Function prototypes exported to rest of GAS. */ +extern void md_assemble (char *op_str); +extern void md_end (void); +extern void md_begin (void); + +#define TC_FORCE_RELOCATION(fixp) nios2_force_relocation (fixp) +extern int nios2_force_relocation (struct fix *); + +#define tc_fix_adjustable(fixp) nios2_fix_adjustable (fixp) +extern int nios2_fix_adjustable (struct fix *); + +#define tc_frob_label(lab) nios2_frob_label (lab) +extern void nios2_frob_label (symbolS *); + +#define tc_frob_symbol(symp, punt) punt = nios2_frob_symbol (symp) ? 1 : punt +extern int nios2_frob_symbol (symbolS * symp); + +#define md_cons_align(nbytes) nios2_cons_align (nbytes) +extern void nios2_cons_align (int); + +extern void md_convert_frag (bfd * headers, segT sec, fragS * fragP); + +/* When relaxing, we need to generate relocations for alignment + directives. */ +#define HANDLE_ALIGN(frag) nios2_handle_align (frag) +extern void nios2_handle_align (fragS *); + +#define md_relax_frag nios2_relax_frag +extern long nios2_relax_frag (segT segment, fragS * fragP, long stretch); + +#ifdef OBJ_ELF +#define ELF_TC_SPECIAL_SECTIONS \ + { ".sdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".sbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".lit4", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".lit8", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, + +/* Processor-specific section directives. */ +#define md_elf_section_letter nios2_elf_section_letter +extern int nios2_elf_section_letter (int, char **); +#define md_elf_section_flags nios2_elf_section_flags +extern flagword nios2_elf_section_flags (flagword, int, int); +#endif + +#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" + +#define DIFF_EXPR_OK + +/* Nios2 ABI doesn't have 32-bit PCREL relocation, and, as relocations for + CFI information will be in section other than .text, we can't use PC-biased + relocs. */ +#define CFI_DIFF_EXPR_OK 0 + +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) nios2_cons (EXP, NBYTES) +extern void nios2_cons (expressionS *exp, int size); + +#define TC_CONS_FIX_NEW nios2_cons_fix_new +extern void nios2_cons_fix_new (struct frag *frag, int where, + unsigned int nbytes, struct expressionS *exp); + +/* We want .cfi_* pseudo-ops for generating unwind info. */ +#define TARGET_USE_CFIPOP 1 +#define DWARF2_DEFAULT_RETURN_COLUMN 31 +#define DWARF2_CIE_DATA_ALIGNMENT (-4) +#define tc_regname_to_dw2regnum nios2_regname_to_dw2regnum +extern int nios2_regname_to_dw2regnum (char *regname); +#define tc_cfi_frame_initial_instructions nios2_frame_initial_instructions +extern void nios2_frame_initial_instructions (void); + +#endif /* TC_NIOS2 */ diff --git a/gas/configure.tgt b/gas/configure.tgt index 8454ab9..9d498e8 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -350,6 +350,8 @@ case ${generic_target} in msp430-*-*) fmt=elf ;; + nios2*-linux*) fmt=elf em=linux ;; + ns32k-pc532-mach*) fmt=aout em=pc532mach ;; ns32k-pc532-ux*) fmt=aout em=pc532mach ;; ns32k-pc532-lites*) fmt=aout em=nbsd532 ;; diff --git a/gas/doc/Makefile.am b/gas/doc/Makefile.am index b200378..3d1e933 100644 --- a/gas/doc/Makefile.am +++ b/gas/doc/Makefile.am @@ -74,6 +74,7 @@ CPU_DOCS = \ c-mmix.texi \ c-mt.texi \ c-msp430.texi \ + c-nios2.texi \ c-ns32k.texi \ c-pdp11.texi \ c-pj.texi \ diff --git a/gas/doc/Makefile.in b/gas/doc/Makefile.in index 9969ff4..4c3c4fb 100644 --- a/gas/doc/Makefile.in +++ b/gas/doc/Makefile.in @@ -316,6 +316,7 @@ CPU_DOCS = \ c-mmix.texi \ c-mt.texi \ c-msp430.texi \ + c-nios2.texi \ c-ns32k.texi \ c-pdp11.texi \ c-pj.texi \ @@ -410,17 +411,17 @@ as.info: as.texinfo $(as_TEXINFOS) fi; \ rm -rf $$backupdir; exit $$rc -as.dvi: as.texinfo $(as_TEXINFOS) +as.dvi: as.texinfo $(as_TEXINFOS) TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) -o $@ `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo -as.pdf: as.texinfo $(as_TEXINFOS) +as.pdf: as.texinfo $(as_TEXINFOS) TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) -o $@ `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo -as.html: as.texinfo $(as_TEXINFOS) +as.html: as.texinfo $(as_TEXINFOS) rm -rf $(@:.html=.htp) if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo; \ diff --git a/gas/doc/all.texi b/gas/doc/all.texi index b213ad7..99dbf8f 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -58,6 +58,7 @@ @set MMIX @set MS1 @set MSP430 +@set NIOSII @set NS32K @set PDP11 @set PJ diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index c976c05..cafcb22 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -431,6 +431,12 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. [@b{--no-expand}] [@b{--no-merge-gregs}] [@b{-x}] [@b{--linker-allocated-gregs}] @end ifset +@ifset NIOSII + +@emph{Target Nios II options:} + [@b{-relax-all}] [@b{-relax-section}] [@b{-no-relax}] + [@b{-EB}] [@b{-EL}] +@end ifset @ifset PDP11 @emph{Target PDP11 options:} @@ -1028,6 +1034,24 @@ unit coprocessor. The default is to assume an MMU for 68020 and up. @end table @end ifset +@ifset NIOSII + +@ifclear man +@xref{Nios II Options}, for the options available when @value{AS} is configured +for an Altera Nios II processor. +@end ifclear + +@ifset man +@c man begin OPTIONS +The following options are available when @value{AS} is configured for an +Altera Nios II processor. +@c man end +@c man begin INCLUDE +@include c-nios2.texi +@c ended inside the included file +@end ifset +@end ifset + @ifset PDP11 For details about the PDP-11 machine dependent features options, @@ -7059,6 +7083,9 @@ subject, see the hardware manufacturer's manual. @ifset MSP430 * MSP430-Dependent:: MSP430 Dependent Features @end ifset +@ifset NIOSII +* NiosII-Dependent:: Altera Nios II Dependent Features +@end ifset @ifset NS32K * NS32K-Dependent:: NS32K Dependent Features @end ifset @@ -7270,6 +7297,10 @@ family. @include c-msp430.texi @end ifset +@ifset NIOSII +@include c-nios2.texi +@end ifset + @ifset NS32K @include c-ns32k.texi @end ifset diff --git a/gas/doc/c-nios2.texi b/gas/doc/c-nios2.texi new file mode 100644 index 0000000..1d45dd2 --- /dev/null +++ b/gas/doc/c-nios2.texi @@ -0,0 +1,249 @@ +@c Copyright 2012, 2013 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@c man end +@ifset GENERIC +@page +@node NiosII-Dependent +@chapter Nios II Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter Nios II Dependent Features +@end ifclear + +@cindex Altera Nios II support +@cindex Nios support +@cindex Nios II support +@menu +* Nios II Options:: Options +* Nios II Syntax:: Syntax +* Nios II Relocations:: Relocations +* Nios II Directives:: Nios II Machine Directives +* Nios II Opcodes:: Opcodes +@end menu + +@node Nios II Options +@section Options +@cindex Nios II options +@cindex options for Nios II + +@c man begin OPTIONS +@table @gcctabopt + +@cindex @code{relax-section} command line option, Nios II +@item -relax-section +Replace identified out-of-range branches with PC-relative @code{jmp} +sequences when possible. The generated code sequences are suitable +for use in position-independent code, but there is a practical limit +on the extended branch range because of the length of the sequences. +This option is the default. + +@cindex @code{relax-all} command line option, Nios II +@item -relax-all +Replace branch instructions not determinable to be in range +and all call instructions with @code{jmp} and @code{callr} sequences +(respectively). This option generates absolute relocations against the +target symbols and is not appropriate for position-independent code. + +@cindex @code{no-relax} command line option, Nios II +@item -no-relax +Do not replace any branches or calls. + +@cindex @code{EB} command line option, Nios II +@item -EB +Generate big-endian output. + +@cindex @code{EL} command line option, Nios II +@item -EL +Generate little-endian output. This is the default. + +@end table +@c man end + +@node Nios II Syntax +@section Syntax +@menu +* Nios II Chars:: Special Characters +@end menu + + +@node Nios II Chars +@subsection Special Characters + +@cindex line comment character, Nios II +@cindex Nios II line comment character +@cindex line separator character, Nios II +@cindex Nios II line separator character +@samp{#} is the line comment character. +@samp{;} is the line separator character. + + +@node Nios II Relocations +@section Nios II Machine Relocations + +@cindex machine relocations, Nios II +@cindex Nios II machine relocations + +@table @code +@cindex @code{hiadj} directive, Nios II +@item %hiadj(@var{expression}) +Extract the upper 16 bits of @var{expression} and add +one if the 15th bit is set. + +The value of @code{%hiadj(@var{expression})} is: +@smallexample +((@var{expression} >> 16) & 0xffff) + ((@var{expression} >> 15) & 0x01) +@end smallexample + +The @code{%hiadj} relocation is intended to be used with +the @code{addi}, @code{ld} or @code{st} instructions +along with a @code{%lo}, in order to load a 32-bit constant. + +@smallexample +movhi r2, %hiadj(symbol) +addi r2, r2, %lo(symbol) +@end smallexample + +@cindex @code{hi} directive, Nios II +@item %hi(@var{expression}) +Extract the upper 16 bits of @var{expression}. + +@cindex @code{lo} directive, Nios II +@item %lo(@var{expression}) +Extract the lower 16 bits of @var{expression}. + +@cindex @code{gprel} directive, Nios II +@item %gprel(@var{expression}) +Subtract the value of the symbol @code{_gp} from +@var{expression}. + +The intention of the @code{%gprel} relocation is +to have a fast small area of memory which only +takes a 16-bit immediate to access. + +@smallexample + .section .sdata +fastint: + .int 123 + .section .text + ldw r4, %gprel(fastint)(gp) +@end smallexample + +@cindex @code{call} directive, Nios II +@cindex @code{got} directive, Nios II +@cindex @code{gotoff} directive, Nios II +@cindex @code{gotoff_lo} directive, Nios II +@cindex @code{gotoff_hiadj} directive, Nios II +@cindex @code{tls_gd} directive, Nios II +@cindex @code{tls_ie} directive, Nios II +@cindex @code{tls_le} directive, Nios II +@cindex @code{tls_ldm} directive, Nios II +@cindex @code{tls_ldo} directive, Nios II +@item %call(@var{expression}) +@itemx %got(@var{expression}) +@itemx %gotoff(@var{expression}) +@itemx %gotoff_lo(@var{expression}) +@itemx %gotoff_hiadj(@var{expression}) +@itemx %tls_gd(@var{expression}) +@itemx %tls_ie(@var{expression}) +@itemx %tls_le(@var{expression}) +@itemx %tls_ldm(@var{expression}) +@itemx %tls_ldo(@var{expression}) + +These relocations support the ABI for Linux Systems documented in the +@cite{Nios II Processor Reference Handbook}. +@end table + + +@node Nios II Directives +@section Nios II Machine Directives + +@cindex machine directives, Nios II +@cindex Nios II machine directives + +@table @code + +@cindex @code{align} directive, Nios II +@item .align @var{expression} [, @var{expression}] +This is the generic @code{.align} directive, however +this aligns to a power of two. + +@cindex @code{half} directive, Nios II +@item .half @var{expression} +Create an aligned constant 2 bytes in size. + +@cindex @code{word} directive, Nios II +@item .word @var{expression} +Create an aligned constant 4 bytes in size. + +@cindex @code{dword} directive, Nios II +@item .dword @var{expression} +Create an aligned constant 8 bytes in size. + +@cindex @code{2byte} directive, Nios II +@item .2byte @var{expression} +Create an unaligned constant 2 bytes in size. + +@cindex @code{4byte} directive, Nios II +@item .4byte @var{expression} +Create an unaligned constant 4 bytes in size. + +@cindex @code{8byte} directive, Nios II +@item .8byte @var{expression} +Create an unaligned constant 8 bytes in size. + +@cindex @code{16byte} directive, Nios II +@item .16byte @var{expression} +Create an unaligned constant 16 bytes in size. + +@cindex @code{set noat} directive, Nios II +@item .set noat +Allows assembly code to use @code{at} register without +warning. Macro or relaxation expansions +generate warnings. + +@cindex @code{set at} directive, Nios II +@item .set at +Assembly code using @code{at} register generates +warnings, and macro expansion and relaxation are +enabled. + +@cindex @code{set nobreak} directive, Nios II +@item .set nobreak +Allows assembly code to use @code{ba} and @code{bt} +registers without warning. + +@cindex @code{set break} directive, Nios II +@item .set break +Turns warnings back on for using @code{ba} and @code{bt} +registers. + +@cindex @code{set norelax} directive, Nios II +@item .set norelax +Do not replace any branches or calls. + +@cindex @code{set relaxsection} directive, Nios II +@item .set relaxsection +Replace identified out-of-range branches with +@code{jmp} sequences (default). + +@cindex @code{set relaxall} directive, Nios II +@item .set relaxsection +Replace all branch and call instructions with +@code{jmp} and @code{callr} sequences. + +@cindex @code{set} directive, Nios II +@item .set @dots{} +All other @code{.set} are the normal use. + +@end table + +@node Nios II Opcodes +@section Opcodes + +@cindex Nios II opcodes +@cindex opcodes for Nios II +@code{@value{AS}} implements all the standard Nios II opcodes documented in the +@cite{Nios II Processor Reference Handbook}, including the assembler +pseudo-instructions. diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index ab91689..e165af4 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,94 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * gas/nios2/add.d: New. + * gas/nios2/add.s: New. + * gas/nios2/align_fill.d: New. + * gas/nios2/align_fill.s: New. + * gas/nios2/align_text.d: New. + * gas/nios2/align_text.s: New. + * gas/nios2/and.d: New. + * gas/nios2/and.s: New. + * gas/nios2/branch.d: New. + * gas/nios2/branch.s: New. + * gas/nios2/break.d: New. + * gas/nios2/break.s: New. + * gas/nios2/bret.d: New. + * gas/nios2/bret.s: New. + * gas/nios2/cache.d: New. + * gas/nios2/cache.s: New. + * gas/nios2/call26.d: New. + * gas/nios2/call26.s: New. + * gas/nios2/call.d: New. + * gas/nios2/call.s: New. + * gas/nios2/cmp.d: New. + * gas/nios2/cmp.s: New. + * gas/nios2/comments.d: New. + * gas/nios2/comments.s: New. + * gas/nios2/complex.d: New. + * gas/nios2/complex.s: New. + * gas/nios2/ctl.d: New. + * gas/nios2/ctl.s: New. + * gas/nios2/custom.d: New. + * gas/nios2/custom.s: New. + * gas/nios2/etbt.d: New. + * gas/nios2/etbt.s: New. + * gas/nios2/flushda.d: New. + * gas/nios2/flushda.s: New. + * gas/nios2/illegal.l: New. + * gas/nios2/illegal.s: New. + * gas/nios2/jmp.d: New. + * gas/nios2/jmp.s: New. + * gas/nios2/ldb.d: New. + * gas/nios2/ldb.s: New. + * gas/nios2/ldh.d: New. + * gas/nios2/ldh.s: New. + * gas/nios2/ldw.d: New. + * gas/nios2/ldw.s: New. + * gas/nios2/lineseparator.d: New. + * gas/nios2/lineseparator.s: New. + * gas/nios2/mov.d: New. + * gas/nios2/movia.d: New. + * gas/nios2/movia.s: New. + * gas/nios2/movi.d: New. + * gas/nios2/movi.s: New. + * gas/nios2/mov.s: New. + * gas/nios2/mul.d: New. + * gas/nios2/mul.s: New. + * gas/nios2/nios2.exp: New. + * gas/nios2/nor.d: New. + * gas/nios2/nor.s: New. + * gas/nios2/or.d: New. + * gas/nios2/or.s: New. + * gas/nios2/ret.d: New. + * gas/nios2/ret.s: New. + * gas/nios2/rol.d: New. + * gas/nios2/rol.s: New. + * gas/nios2/rotate.d: New. + * gas/nios2/rotate.s: New. + * gas/nios2/stb.d: New. + * gas/nios2/stb.s: New. + * gas/nios2/sth.d: New. + * gas/nios2/sth.s: New. + * gas/nios2/stw.d: New. + * gas/nios2/stw.s: New. + * gas/nios2/sub.d: New. + * gas/nios2/sub.s: New. + * gas/nios2/sync.d: New. + * gas/nios2/sync.s: New. + * gas/nios2/trap.d: New. + * gas/nios2/trap.s: New. + * gas/nios2/tret.d: New. + * gas/nios2/tret.s: New. + * gas/nios2/warn_noat.l: New. + * gas/nios2/warn_noat.s: New. + * gas/nios2/warn_nobreak.l: New. + * gas/nios2/warn_nobreak.s: New. + * gas/nios2/xor.d: New. + * gas/nios2/xor.s: New. + 2013-01-31 Tristan Gingold <gingold@adacore.com> * gas/ppc/test1xcoff32.d: Updated. diff --git a/gas/testsuite/gas/nios2/add.d b/gas/testsuite/gas/nios2/add.d new file mode 100644 index 0000000..ba3d27f --- /dev/null +++ b/gas/testsuite/gas/nios2/add.d @@ -0,0 +1,16 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 add + +# Test the add instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> add r4,r4,r4 +0+0004 <[^>]*> addi r4,r4,32767 +0+0008 <[^>]*> addi r4,r4,-32768 +0+000c <[^>]*> addi r4,r4,0 +0+0010 <[^>]*> addi r4,r4,-1 +0+0014 <[^>]*> addi r4,r4,-1 +0+0018 <[^>]*> addi r4,r4,13398 +0+001c <[^>]*> nop diff --git a/gas/testsuite/gas/nios2/add.s b/gas/testsuite/gas/nios2/add.s new file mode 100644 index 0000000..5b72a82 --- /dev/null +++ b/gas/testsuite/gas/nios2/add.s @@ -0,0 +1,13 @@ +# Source file used to test the add and addi instructions. + +foo: + add r4,r4,r4 + addi r4,r4,0x7fff + addi r4,r4,-0x8000 + addi r4,r4,0x0 + addi r4,r4,-0x01 + subi r4,r4,0x01 + addi r4,r4,0x3456 + +# should disassemble to add r0,0,r0 + nop diff --git a/gas/testsuite/gas/nios2/align_fill.d b/gas/testsuite/gas/nios2/align_fill.d new file mode 100644 index 0000000..90a9e5f --- /dev/null +++ b/gas/testsuite/gas/nios2/align_fill.d @@ -0,0 +1,23 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 align_fill + +# Test the and macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> addi sp,sp,-8 +0+0004 <[^>]*> stw fp,4\(sp\) +0+0008 <[^>]*> mov fp,sp +0+000c <[^>]*> mov r3,zero +0+0010 <[^>]*> nop +0+0014 <[^>]*> nop +0+0018 <[^>]*> nop +0+001c <[^>]*> nop +0+0020 <[^>]*> addi r3,r3,1 +0+0024 <[^>]*> cmplti r2,r3,100 +0+0028 <[^>]*> bne r2,zero,0+0020 <[^>*]*> +0+002c <[^>]*> ldw fp,4\(sp\) +0+0030 <[^>]*> addi sp,sp,8 +0+0034 <[^>]*> ret + ... diff --git a/gas/testsuite/gas/nios2/align_fill.s b/gas/testsuite/gas/nios2/align_fill.s new file mode 100644 index 0000000..5683839 --- /dev/null +++ b/gas/testsuite/gas/nios2/align_fill.s @@ -0,0 +1,20 @@ + .file "a.c" + .section .text + .align 3 + .global x + .type x, @function +x: + addi sp, sp, -8 + stw fp, 4(sp) + mov fp, sp + mov r3, zero + .align 5 +.L6: + addi r3, r3, 1 + cmplti r2, r3, 100 + bne r2, zero, .L6 + ldw fp, 4(sp) + addi sp, sp, 8 + ret + .size x, .-x + .ident "GCC: (GNU) 3.3.3 (Altera Nios II 1.0 b302)" diff --git a/gas/testsuite/gas/nios2/align_text.d b/gas/testsuite/gas/nios2/align_text.d new file mode 100644 index 0000000..80611e7 --- /dev/null +++ b/gas/testsuite/gas/nios2/align_text.d @@ -0,0 +1,22 @@ +#objdump: -dr +#name: NIOS2 align_test + +# Test alignment in text sections. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +00000000 <label-0x20>: + 0: 00000000 call 0 <label-0x20> + 4: 0001883a nop + 8: 0001883a nop + c: 0001883a nop + 10: 0001883a nop + 14: 0001883a nop + 18: 0001883a nop + 1c: 0001883a nop + +00000020 <label>: + 20: 0001883a nop +00000024 <label2>: + ... diff --git a/gas/testsuite/gas/nios2/align_text.s b/gas/testsuite/gas/nios2/align_text.s new file mode 100644 index 0000000..d073b6f --- /dev/null +++ b/gas/testsuite/gas/nios2/align_text.s @@ -0,0 +1,15 @@ + .asciz "" # empty string + .align 2 + + nop + nop + label: + .align 5 + nop + label2: + .section mysection + .align 2 + + + + diff --git a/gas/testsuite/gas/nios2/and.d b/gas/testsuite/gas/nios2/and.d new file mode 100644 index 0000000..350ca69 --- /dev/null +++ b/gas/testsuite/gas/nios2/and.d @@ -0,0 +1,17 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 and + +# Test the and macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> and r4,r4,r4 +0+0004 <[^>]*> andi r4,r4,32767 +0+0008 <[^>]*> andi r4,r4,32768 +0+000c <[^>]*> andi r4,r4,65535 +0+0010 <[^>]*> andi r4,r4,0 +0+0014 <[^>]*> andhi r4,r4,32767 +0+0018 <[^>]*> andhi r4,r4,32768 +0+001c <[^>]*> andhi r4,r4,65535 +0+0020 <[^>]*> andhi r4,r4,0 diff --git a/gas/testsuite/gas/nios2/and.s b/gas/testsuite/gas/nios2/and.s new file mode 100644 index 0000000..946a8b8 --- /dev/null +++ b/gas/testsuite/gas/nios2/and.s @@ -0,0 +1,13 @@ +# Source file used to test the and, andhi and andi instructions + +foo: + and r4,r4,r4 + andi r4,r4,0x7fff + andi r4,r4,0x8000 + andi r4,r4,0xffff + andi r4,r4,0x0 + andhi r4,r4,0x7fff + andhi r4,r4,0x8000 + andhi r4,r4,0xffff + andhi r4,r4,0x0 + diff --git a/gas/testsuite/gas/nios2/branch.d b/gas/testsuite/gas/nios2/branch.d new file mode 100644 index 0000000..08d20f3 --- /dev/null +++ b/gas/testsuite/gas/nios2/branch.d @@ -0,0 +1,21 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 branch + +# Test the branch instructions. +dump.o: file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> beq r4,r5,00000004 <text_label\+0x4> +[ ]*0: R_NIOS2_PCREL16 text_label +0+0004 <[^>]*> bge r4,r5,00000008 <text_label\+0x8> +[ ]*4: R_NIOS2_PCREL16 text_label +0+0008 <[^>]*> bgeu r4,r5,0000000c <text_label\+0xc> +[ ]*8: R_NIOS2_PCREL16 text_label +0+000c <[^>]*> blt r4,r5,00000010 <text_label\+0x10> +[ ]*c: R_NIOS2_PCREL16 text_label +0+0010 <[^>]*> bltu r4,r5,00000014 <text_label\+0x14> +[ ]*10: R_NIOS2_PCREL16 text_label +0+0014 <[^>]*> bne r4,r5,00000018 <text_label\+0x18> +[ ]*14: R_NIOS2_PCREL16 text_label +0+0018 <[^>]*> br 0000001c <text_label\+0x1c> +[ ]*18: R_NIOS2_PCREL16 external_label diff --git a/gas/testsuite/gas/nios2/branch.s b/gas/testsuite/gas/nios2/branch.s new file mode 100644 index 0000000..0853167 --- /dev/null +++ b/gas/testsuite/gas/nios2/branch.s @@ -0,0 +1,15 @@ +# Source file used to test the beq macro. + .globl text_label + .text +.set norelax +text_label: + beq r4,r5,text_label + bge r4,r5,text_label + bgeu r4,r5,text_label + blt r4,r5,text_label + bltu r4,r5,text_label + bne r4,r5,text_label + +# Branch to an external label. + br external_label + diff --git a/gas/testsuite/gas/nios2/break.d b/gas/testsuite/gas/nios2/break.d new file mode 100644 index 0000000..be487bb --- /dev/null +++ b/gas/testsuite/gas/nios2/break.d @@ -0,0 +1,12 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 break + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> break 0 +0+0004 <[^>]*> break 0 +0+0008 <[^>]*> break 31 +0+000c <[^>]*> break 14 + + diff --git a/gas/testsuite/gas/nios2/break.s b/gas/testsuite/gas/nios2/break.s new file mode 100644 index 0000000..88d3422 --- /dev/null +++ b/gas/testsuite/gas/nios2/break.s @@ -0,0 +1,8 @@ +# Source file used to test the 20-bit break instructions +foo: + break + break 0 + break 31 + break 14 + + diff --git a/gas/testsuite/gas/nios2/bret.d b/gas/testsuite/gas/nios2/bret.d new file mode 100644 index 0000000..a12530b --- /dev/null +++ b/gas/testsuite/gas/nios2/bret.d @@ -0,0 +1,8 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 bret + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> bret + diff --git a/gas/testsuite/gas/nios2/bret.s b/gas/testsuite/gas/nios2/bret.s new file mode 100644 index 0000000..d368e64 --- /dev/null +++ b/gas/testsuite/gas/nios2/bret.s @@ -0,0 +1,5 @@ +# Source file used to test the bret instructions +foo: + bret + + diff --git a/gas/testsuite/gas/nios2/cache.d b/gas/testsuite/gas/nios2/cache.d new file mode 100644 index 0000000..7c278d8 --- /dev/null +++ b/gas/testsuite/gas/nios2/cache.d @@ -0,0 +1,17 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 cache + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> flushd -32768\(r6\) +0+0004 <[^>]*> flushd 32767\(r6\) +0+0008 <[^>]*> flushd 0\(r6\) +0+000c <[^>]*> flushd -1\(r6\) +0+0010 <[^>]*> flushd 0\(r6\) +[ ]*10: R_NIOS2_S16 .text +0+0014 <[^>]*> flushd 0\(r6\) +[ ]*14: R_NIOS2_S16 external +0+0018 <[^>]*> flushi r2 +0+001c <[^>]*> flushp + diff --git a/gas/testsuite/gas/nios2/cache.s b/gas/testsuite/gas/nios2/cache.s new file mode 100644 index 0000000..1701c19 --- /dev/null +++ b/gas/testsuite/gas/nios2/cache.s @@ -0,0 +1,21 @@ +# Source file used to test the cache instruction +foo: + flushd -0x8000(r6) + flushd 0x7fff(r6) + flushd 0x0(r6) + flushd -0x0001(r6) + +# use symbol for offset + flushd foo(r6) + +# use external symbol + .global external + flushd external(r6) + +# flushi + flushi r2 + +#flushp + flushp + + diff --git a/gas/testsuite/gas/nios2/call.d b/gas/testsuite/gas/nios2/call.d new file mode 100644 index 0000000..cfa6aec --- /dev/null +++ b/gas/testsuite/gas/nios2/call.d @@ -0,0 +1,11 @@ +# objdump: -dr --prefix-addresses +#name: NIOS2 call + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> call 00000000 <foo> +[ ]*0: R_NIOS2_CALL26 .text\+0xc +0+0004 <[^>]*> callr r10 +0+0008 <[^>]*> call 00000000 <foo> +[ ]*8: R_NIOS2_CALL26 external diff --git a/gas/testsuite/gas/nios2/call.s b/gas/testsuite/gas/nios2/call.s new file mode 100644 index 0000000..39409b7 --- /dev/null +++ b/gas/testsuite/gas/nios2/call.s @@ -0,0 +1,13 @@ +# Source file used to test the call and callr instructions +.text +.set norelax +foo: + call func1 + callr r10 +# use external symbol + .global external + call external +func1: + + + diff --git a/gas/testsuite/gas/nios2/call26.d b/gas/testsuite/gas/nios2/call26.d new file mode 100644 index 0000000..63364ef --- /dev/null +++ b/gas/testsuite/gas/nios2/call26.d @@ -0,0 +1,76 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 nios2-reloc-r-nios2-call26 + +# Test the branch instructions. +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +[ ]*\.\.\. +[ ]*0: R_NIOS2_CALL26 .text\+0x100 +[ ]*4: R_NIOS2_CALL26 globalfunc +0+0008 <[^>]*> nop +0+000c <[^>]*> nop +0+0010 <[^>]*> nop +0+0014 <[^>]*> nop +0+0018 <[^>]*> nop +0+001c <[^>]*> nop +0+0020 <[^>]*> nop +0+0024 <[^>]*> nop +0+0028 <[^>]*> nop +0+002c <[^>]*> nop +0+0030 <[^>]*> nop +0+0034 <[^>]*> nop +0+0038 <[^>]*> nop +0+003c <[^>]*> nop +0+0040 <[^>]*> nop +0+0044 <[^>]*> nop +0+0048 <[^>]*> nop +0+004c <[^>]*> nop +0+0050 <[^>]*> nop +0+0054 <[^>]*> nop +0+0058 <[^>]*> nop +0+005c <[^>]*> nop +0+0060 <[^>]*> nop +0+0064 <[^>]*> nop +0+0068 <[^>]*> nop +0+006c <[^>]*> nop +0+0070 <[^>]*> nop +0+0074 <[^>]*> nop +0+0078 <[^>]*> nop +0+007c <[^>]*> nop +0+0080 <[^>]*> nop +0+0084 <[^>]*> nop +0+0088 <[^>]*> nop +0+008c <[^>]*> nop +0+0090 <[^>]*> nop +0+0094 <[^>]*> nop +0+0098 <[^>]*> nop +0+009c <[^>]*> nop +0+00a0 <[^>]*> nop +0+00a4 <[^>]*> nop +0+00a8 <[^>]*> nop +0+00ac <[^>]*> nop +0+00b0 <[^>]*> nop +0+00b4 <[^>]*> nop +0+00b8 <[^>]*> nop +0+00bc <[^>]*> nop +0+00c0 <[^>]*> nop +0+00c4 <[^>]*> nop +0+00c8 <[^>]*> nop +0+00cc <[^>]*> nop +0+00d0 <[^>]*> nop +0+00d4 <[^>]*> nop +0+00d8 <[^>]*> nop +0+00dc <[^>]*> nop +0+00e0 <[^>]*> nop +0+00e4 <[^>]*> nop +0+00e8 <[^>]*> nop +0+00ec <[^>]*> nop +0+00f0 <[^>]*> nop +0+00f4 <[^>]*> nop +0+00f8 <[^>]*> nop +0+00fc <[^>]*> nop +0+0100 <[^>]*> nop + ... + + diff --git a/gas/testsuite/gas/nios2/call26.s b/gas/testsuite/gas/nios2/call26.s new file mode 100644 index 0000000..dd128a7 --- /dev/null +++ b/gas/testsuite/gas/nios2/call26.s @@ -0,0 +1,12 @@ +# Test for Nios II 32-bit relocations + +.global globalfunc +.text +.set norelax +start: + call localfunc + call globalfunc + +.align 8 +localfunc: + nop diff --git a/gas/testsuite/gas/nios2/cmp.d b/gas/testsuite/gas/nios2/cmp.d new file mode 100644 index 0000000..43d9d68 --- /dev/null +++ b/gas/testsuite/gas/nios2/cmp.d @@ -0,0 +1,24 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 cmp + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> cmpeq r11,r2,r3 +0+0004 <[^>]*> cmpge r11,r2,r3 +0+0008 <[^>]*> cmpgeu r11,r2,r3 +0+000c <[^>]*> cmplt r11,r2,r3 +0+0010 <[^>]*> cmpltu r11,r2,r3 +0+0014 <[^>]*> cmpne r11,r2,r3 +0+0018 <[^>]*> cmpgei r11,r2,0 +[ ]*18: R_NIOS2_S16 value +0+001c <[^>]*> cmpgeui r11,r2,0 +[ ]*1c: R_NIOS2_U16 value\+0x200 +0+0020 <[^>]*> cmplti r11,r2,0 +[ ]*20: R_NIOS2_S16 value +0+0024 <[^>]*> cmpltui r11,r2,0 +[ ]*24: R_NIOS2_U16 value\+0x200 +0+0028 <[^>]*> cmpgei r11,r2,32767 +0+002c <[^>]*> cmpgeui r11,r2,32768 +0+0030 <[^>]*> cmplti r11,r2,-32768 +0+0034 <[^>]*> cmpltui r11,r2,65535 diff --git a/gas/testsuite/gas/nios2/cmp.s b/gas/testsuite/gas/nios2/cmp.s new file mode 100644 index 0000000..6f7c15b --- /dev/null +++ b/gas/testsuite/gas/nios2/cmp.s @@ -0,0 +1,22 @@ +# Source file used to test the compare instructions +foo: + cmpeq r11,r2,r3 + cmpge r11,r2,r3 + cmpgeu r11,r2,r3 + cmplt r11,r2,r3 + cmpltu r11,r2,r3 + cmpne r11,r2,r3 +# test that cmp generates relocations correctly + cmpgei r11,r2,value + cmpgeui r11,r2,value+0x200 + cmplti r11,r2,value + cmpltui r11,r2,value+0x200 + + cmpgei r11,r2,0x7fff + cmpgeui r11,r2,0x8000 + cmplti r11,r2,-0x8000 + cmpltui r11,r2,0xFFFF +.global value + + + diff --git a/gas/testsuite/gas/nios2/comments.d b/gas/testsuite/gas/nios2/comments.d new file mode 100644 index 0000000..890dcc2 --- /dev/null +++ b/gas/testsuite/gas/nios2/comments.d @@ -0,0 +1,26 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 comments + +# Test the add instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> br 0000001c <start> +0+0004 <[^>]*> br 00000008 <abort> +0+0008 <[^>]*> movui r3,0 +0+000c <[^>]*> movui r2,1 +0+0010 <[^>]*> movui r3,0 +0+0014 <[^>]*> movui r2,0 +0+0018 <[^>]*> br 00000044 <exit> +0+001c <[^>]*> addi r2,r2,-4 +0+0020 <[^>]*> movui r11,1 +0+0024 <[^>]*> movui r5,0 +0+0028 <[^>]*> movui r6,0 +0+002c <[^>]*> br 00000030 <ldst> +0+0030 <[^>]*> movui r2,61452 +0+0034 <[^>]*> movui r20,64206 +0+0038 <[^>]*> stw r20,0\(r2\) +0+003c <[^>]*> ldw r21,0\(r2\) +0+0040 <[^>]*> br 00000010 <end> +0+0044 <[^>]*> br 00000044 <exit> diff --git a/gas/testsuite/gas/nios2/comments.s b/gas/testsuite/gas/nios2/comments.s new file mode 100644 index 0000000..7ab2027 --- /dev/null +++ b/gas/testsuite/gas/nios2/comments.s @@ -0,0 +1,28 @@ +.set norelax +_main: br start +trap: + br abort +.globl _main +abort: movui r3, 0x0 + movui r2, 0x1 + +end: movui r3, 0x0 + movui r2, 0x0 + br exit + +start: + addi r2, r2, -4 # test for ve numbers + movui r11, 0x1 + ori r5, r0, %lo(0x0) # r5 = 0x0 + ori r6, r0, %lo(0x0) # r6 = 0x0 + br ldst + +ldst: + movui r2, 0xF00C + movui r20, 0xFACE + stw r20,(r2) + ldw r21, (r2) + br end + + +exit: br exit diff --git a/gas/testsuite/gas/nios2/complex.d b/gas/testsuite/gas/nios2/complex.d new file mode 100644 index 0000000..f32115b --- /dev/null +++ b/gas/testsuite/gas/nios2/complex.d @@ -0,0 +1,12 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 complex + +# Test complex expression parsing + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> ldw r2,-1\(r3\) +0+0004 <[^>]*> ldw r2,1\(r3\) +0+0008 <[^>]*> ldw r2,0\(r3\) + 8: R_NIOS2_S16 stack_top-0x1 diff --git a/gas/testsuite/gas/nios2/complex.s b/gas/testsuite/gas/nios2/complex.s new file mode 100644 index 0000000..65141f9 --- /dev/null +++ b/gas/testsuite/gas/nios2/complex.s @@ -0,0 +1,5 @@ +foo: + ldw r2, (2-3)(r3) + ldw r2, 2 + (2-3)(r3) + ldw r2, 2 + (stack_top-3)(r3) + diff --git a/gas/testsuite/gas/nios2/ctl.d b/gas/testsuite/gas/nios2/ctl.d new file mode 100644 index 0000000..f698ce6 --- /dev/null +++ b/gas/testsuite/gas/nios2/ctl.d @@ -0,0 +1,20 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 ctl + +# Test the ctl instructions + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> rdctl r8,ctl31 +0+0004 <[^>]*> rdctl r8,ctl30 +0+0008 <[^>]*> rdctl r8,ctl29 +0+000c <[^>]*> rdctl r8,status +0+0010 <[^>]*> rdctl r8,bstatus +0+0014 <[^>]*> rdctl r8,estatus +0+0018 <[^>]*> wrctl ctl31,r8 +0+001c <[^>]*> wrctl ctl30,r8 +0+0020 <[^>]*> wrctl ctl29,r8 +0+0024 <[^>]*> wrctl status,r8 +0+0028 <[^>]*> wrctl bstatus,r8 +0+002c <[^>]*> wrctl estatus,r8 diff --git a/gas/testsuite/gas/nios2/ctl.s b/gas/testsuite/gas/nios2/ctl.s new file mode 100644 index 0000000..dc6c983 --- /dev/null +++ b/gas/testsuite/gas/nios2/ctl.s @@ -0,0 +1,18 @@ +# Source file used to test the nor instruction + +foo: + rdctl r8,ctl31 + rdctl r8,ctl30 + rdctl r8,ctl29 + rdctl r8,status + rdctl r8,bstatus + rdctl r8,estatus + wrctl ctl31,r8 + wrctl ctl30,r8 + wrctl ctl29,r8 + wrctl status,r8 + wrctl bstatus,r8 + wrctl estatus,r8 + + + diff --git a/gas/testsuite/gas/nios2/custom.d b/gas/testsuite/gas/nios2/custom.d new file mode 100644 index 0000000..c1e17be --- /dev/null +++ b/gas/testsuite/gas/nios2/custom.d @@ -0,0 +1,13 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 custom + +# Test the custom instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> custom 0,r11,r2,r3 +0+0004 <[^>]*> custom 255,r11,r2,r3 +0+0008 <[^>]*> custom 150,c1,r2,r3 +0+000c <[^>]*> custom 24,c1,c2,r3 +0+0010 <[^>]*> custom 56,c1,c2,c3 diff --git a/gas/testsuite/gas/nios2/custom.s b/gas/testsuite/gas/nios2/custom.s new file mode 100644 index 0000000..903122a --- /dev/null +++ b/gas/testsuite/gas/nios2/custom.s @@ -0,0 +1,8 @@ +# test progam for assembling user instructions + +foo: + custom 0, r11, r2, r3 + custom 255, r11, r2, r3 + custom 150, c1, r2, r3 + custom 0x18, c1, c2, r3 + custom 070, c1, c2, c3 diff --git a/gas/testsuite/gas/nios2/etbt.d b/gas/testsuite/gas/nios2/etbt.d new file mode 100644 index 0000000..58b8e32 --- /dev/null +++ b/gas/testsuite/gas/nios2/etbt.d @@ -0,0 +1,10 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 etbt + +# Test the et, bt registers + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> add et,bt,r6 +0+0004 <[^>]*> add et,bt,r6 diff --git a/gas/testsuite/gas/nios2/etbt.s b/gas/testsuite/gas/nios2/etbt.s new file mode 100644 index 0000000..3e5fc24 --- /dev/null +++ b/gas/testsuite/gas/nios2/etbt.s @@ -0,0 +1,4 @@ +.set nobreak +foo: + add r24, r25, r6 + add et, bt, r6 diff --git a/gas/testsuite/gas/nios2/flushda.d b/gas/testsuite/gas/nios2/flushda.d new file mode 100644 index 0000000..f3b5e3e --- /dev/null +++ b/gas/testsuite/gas/nios2/flushda.d @@ -0,0 +1,10 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 flushda + +# Test the jmp instruction. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> flushda 12\(r2\) + diff --git a/gas/testsuite/gas/nios2/flushda.s b/gas/testsuite/gas/nios2/flushda.s new file mode 100644 index 0000000..3a32474 --- /dev/null +++ b/gas/testsuite/gas/nios2/flushda.s @@ -0,0 +1,6 @@ +# Source file used to test the flushda instruction. +.text +.set nobreak +foo: + flushda 12(r2) + diff --git a/gas/testsuite/gas/nios2/illegal.l b/gas/testsuite/gas/nios2/illegal.l new file mode 100644 index 0000000..6248567 --- /dev/null +++ b/gas/testsuite/gas/nios2/illegal.l @@ -0,0 +1,14 @@ +.*illegal.s: Assembler messages: +.*illegal.s:5: Error: unknown register r56 +.*illegal.s:8: Error: expecting \( near 0x1000 +.*illegal.s:8: Error: missing argument +.*illegal.s:9: Error: expecting \) near r5 +.*illegal.s:10: Error: expecting \( near 0x1000r5\) +.*illegal.s:10: Error: missing argument +.*illegal.s:11: Error: expecting \( near 0x1000,r5 +.*illegal.s:11: Error: missing argument +.*illegal.s:12: Error: unknown register 0x1000 +.*illegal.s:14: Error: unrecognised instruction fop +.*illegal.s:16: Error: too many arguments +.*illegal.s:17: Error: too many arguments +.*illegal.s:17: Error: unknown register r2,r4 diff --git a/gas/testsuite/gas/nios2/illegal.s b/gas/testsuite/gas/nios2/illegal.s new file mode 100644 index 0000000..75b6d89 --- /dev/null +++ b/gas/testsuite/gas/nios2/illegal.s @@ -0,0 +1,17 @@ +# Source file used to test illegal operands. + +foo: +# Illegal registers + add r3,r4,r56 + add r4,r0,r2 +# Illegal syntax + ldw r4,0x1000 + ldw r4,0x1000(r5 + ldw r4,0x1000r5) + ldw r4,0x1000,r5 + ldw r4,(0x1000)r5 +# Illegal opcodes + fop r3,r4,r5 +# Extra operands + nop Crapola + add r2, r2, r2, r4 diff --git a/gas/testsuite/gas/nios2/jmp.d b/gas/testsuite/gas/nios2/jmp.d new file mode 100644 index 0000000..b8727b3 --- /dev/null +++ b/gas/testsuite/gas/nios2/jmp.d @@ -0,0 +1,10 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 jmp + +# Test the jmp instruction. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> jmp bt + diff --git a/gas/testsuite/gas/nios2/jmp.s b/gas/testsuite/gas/nios2/jmp.s new file mode 100644 index 0000000..8d859f2 --- /dev/null +++ b/gas/testsuite/gas/nios2/jmp.s @@ -0,0 +1,6 @@ +# Source file used to test the jmp instruction. +.text +.set nobreak +foo: + jmp r25 + diff --git a/gas/testsuite/gas/nios2/ldb.d b/gas/testsuite/gas/nios2/ldb.d new file mode 100644 index 0000000..5a417b8 --- /dev/null +++ b/gas/testsuite/gas/nios2/ldb.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 ldb + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> ldb r4,0\(zero\) +0+0004 <[^>]*> ldb r4,4\(zero\) +0+0008 <[^>]*> ldb r4,32764\(zero\) +0+000c <[^>]*> ldb r4,-32768\(zero\) +0+0010 <[^>]*> ldb r4,0\(r5\) +0+0014 <[^>]*> ldb r4,4\(r5\) +0+0018 <[^>]*> ldb r4,32764\(r5\) +0+001c <[^>]*> ldb r4,-32768\(r5\) +0+0020 <[^>]*> ldb r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> ldb r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> ldb r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> ldb r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> ldb r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> ldb r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> ldb r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> ldb r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> ldb r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> ldb r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> ldb r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> ldb r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> ldb r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> ldb r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> ldb r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> ldb r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> ldb r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> ldb r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> ldb r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> ldb r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> ldb r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> ldb r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> ldb r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> ldb r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> ldb r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> ldb r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> ldb r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> ldb r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> ldb r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> ldb r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> ldb r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> ldb r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> ldb r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> ldb r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> ldb r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> ldb r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> ldb r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> ldb r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> ldb r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> ldb r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> ldb r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> ldb r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> ldb r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> ldbio r4,0\(zero\) +0+00d0 <[^>]*> ldbio r4,4\(zero\) +0+00d4 <[^>]*> ldbio r4,32764\(zero\) +0+00d8 <[^>]*> ldbio r4,-32768\(zero\) +0+00dc <[^>]*> ldbio r4,0\(r5\) +0+00e0 <[^>]*> ldbio r4,4\(r5\) +0+00e4 <[^>]*> ldbio r4,32764\(r5\) +0+00e8 <[^>]*> ldbio r4,-32768\(r5\) +0+00ec <[^>]*> ldbio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> ldbio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> ldbio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> ldbio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> ldbio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> ldbio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> ldbio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> ldbio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> ldbio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> ldbio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> ldbio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> ldbio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> ldbio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> ldbio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> ldbio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> ldbio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> ldbio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> ldbio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> ldbio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> ldbio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> ldbio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> ldbio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> ldbio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> ldbio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> ldbio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> ldbio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> ldbio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> ldbio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> ldbio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> ldbio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> ldbio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> ldbio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> ldbio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> ldbio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> ldbio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> ldbio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> ldbio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> ldbio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> ldbio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> ldbio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> ldbio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> ldbio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> ldbio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/ldb.s b/gas/testsuite/gas/nios2/ldb.s new file mode 100644 index 0000000..71c51f1 --- /dev/null +++ b/gas/testsuite/gas/nios2/ldb.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + ldb r4,0(r0) + ldb r4,4(r0) + ldb r4,0x7ffc(r0) + ldb r4,-0x8000(r0) + ldb r4,0(r5) + ldb r4,4(r5) + ldb r4,0x7ffc(r5) + ldb r4,-0x8000(r5) + ldb r4,data_label(r0) + ldb r4,big_external_data_label(r0) + ldb r4,small_external_data_label(r0) + ldb r4,big_external_common(r0) + ldb r4,small_external_common(r0) + ldb r4,big_local_common(r0) + ldb r4,small_local_common(r0) + ldb r4,data_label+4(r0) + ldb r4,big_external_data_label+4(r0) + ldb r4,small_external_data_label+4(r0) + ldb r4,big_external_common+4(r0) + ldb r4,small_external_common+4(r0) + ldb r4,big_local_common+4(r0) + ldb r4,small_local_common+4(r0) + ldb r4,data_label-0x8000(r0) + ldb r4,big_external_data_label-0x8000(r0) + ldb r4,small_external_data_label-0x8000(r0) + ldb r4,big_external_common-0x8000(r0) + ldb r4,small_external_common-0x8000(r0) + ldb r4,big_local_common-0x8000(r0) + ldb r4,small_local_common-0x8000(r0) + ldb r4,data_label+0x10000(r0) + ldb r4,data_label(r5) + ldb r4,big_external_data_label(r5) + ldb r4,small_external_data_label(r5) + ldb r4,big_external_common(r5) + ldb r4,small_external_common(r5) + ldb r4,big_local_common(r5) + ldb r4,small_local_common(r5) + ldb r4,data_label+4(r5) + ldb r4,big_external_data_label+4(r5) + ldb r4,small_external_data_label+4(r5) + ldb r4,big_external_common+4(r5) + ldb r4,small_external_common+4(r5) + ldb r4,big_local_common+4(r5) + ldb r4,small_local_common+4(r5) + ldb r4,data_label-0x8000(r5) + ldb r4,big_external_data_label-0x8000(r5) + ldb r4,small_external_data_label-0x8000(r5) + ldb r4,big_external_common-0x8000(r5) + ldb r4,small_external_common-0x8000(r5) + ldb r4,big_local_common-0x8000(r5) + ldb r4,small_local_common-0x8000(r5) + + ldbio r4,0(r0) + ldbio r4,4(r0) + ldbio r4,0x7ffc(r0) + ldbio r4,-0x8000(r0) + ldbio r4,0(r5) + ldbio r4,4(r5) + ldbio r4,0x7ffc(r5) + ldbio r4,-0x8000(r5) + ldbio r4,data_label(r0) + ldbio r4,big_external_data_label(r0) + ldbio r4,small_external_data_label(r0) + ldbio r4,big_external_common(r0) + ldbio r4,small_external_common(r0) + ldbio r4,big_local_common(r0) + ldbio r4,small_local_common(r0) + ldbio r4,data_label+4(r0) + ldbio r4,big_external_data_label+4(r0) + ldbio r4,small_external_data_label+4(r0) + ldbio r4,big_external_common+4(r0) + ldbio r4,small_external_common+4(r0) + ldbio r4,big_local_common+4(r0) + ldbio r4,small_local_common+4(r0) + ldbio r4,data_label-0x8000(r0) + ldbio r4,big_external_data_label-0x8000(r0) + ldbio r4,small_external_data_label-0x8000(r0) + ldbio r4,big_external_common-0x8000(r0) + ldbio r4,small_external_common-0x8000(r0) + ldbio r4,big_local_common-0x8000(r0) + ldbio r4,small_local_common-0x8000(r0) + ldbio r4,data_label+0x10000(r0) + ldbio r4,data_label(r5) + ldbio r4,big_external_data_label(r5) + ldbio r4,small_external_data_label(r5) + ldbio r4,big_external_common(r5) + ldbio r4,small_external_common(r5) + ldbio r4,big_local_common(r5) + ldbio r4,small_local_common(r5) + ldbio r4,data_label+4(r5) + ldbio r4,big_external_data_label+4(r5) + ldbio r4,small_external_data_label+4(r5) + ldbio r4,big_external_common+4(r5) + ldbio r4,small_external_common+4(r5) + ldbio r4,big_local_common+4(r5) + ldbio r4,small_local_common+4(r5) + ldbio r4,data_label-0x8000(r5) + ldbio r4,big_external_data_label-0x8000(r5) + ldbio r4,small_external_data_label-0x8000(r5) + ldbio r4,big_external_common-0x8000(r5) + ldbio r4,small_external_common-0x8000(r5) + ldbio r4,big_local_common-0x8000(r5) + ldbio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/ldh.d b/gas/testsuite/gas/nios2/ldh.d new file mode 100644 index 0000000..f030eef --- /dev/null +++ b/gas/testsuite/gas/nios2/ldh.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 ldh + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> ldh r4,0\(zero\) +0+0004 <[^>]*> ldh r4,4\(zero\) +0+0008 <[^>]*> ldh r4,32764\(zero\) +0+000c <[^>]*> ldh r4,-32768\(zero\) +0+0010 <[^>]*> ldh r4,0\(r5\) +0+0014 <[^>]*> ldh r4,4\(r5\) +0+0018 <[^>]*> ldh r4,32764\(r5\) +0+001c <[^>]*> ldh r4,-32768\(r5\) +0+0020 <[^>]*> ldh r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> ldh r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> ldh r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> ldh r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> ldh r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> ldh r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> ldh r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> ldh r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> ldh r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> ldh r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> ldh r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> ldh r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> ldh r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> ldh r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> ldh r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> ldh r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> ldh r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> ldh r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> ldh r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> ldh r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> ldh r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> ldh r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> ldh r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> ldh r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> ldh r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> ldh r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> ldh r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> ldh r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> ldh r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> ldh r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> ldh r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> ldh r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> ldh r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> ldh r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> ldh r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> ldh r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> ldh r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> ldh r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> ldh r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> ldh r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> ldh r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> ldh r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> ldh r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> ldhio r4,0\(zero\) +0+00d0 <[^>]*> ldhio r4,4\(zero\) +0+00d4 <[^>]*> ldhio r4,32764\(zero\) +0+00d8 <[^>]*> ldhio r4,-32768\(zero\) +0+00dc <[^>]*> ldhio r4,0\(r5\) +0+00e0 <[^>]*> ldhio r4,4\(r5\) +0+00e4 <[^>]*> ldhio r4,32764\(r5\) +0+00e8 <[^>]*> ldhio r4,-32768\(r5\) +0+00ec <[^>]*> ldhio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> ldhio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> ldhio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> ldhio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> ldhio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> ldhio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> ldhio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> ldhio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> ldhio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> ldhio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> ldhio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> ldhio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> ldhio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> ldhio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> ldhio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> ldhio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> ldhio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> ldhio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> ldhio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> ldhio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> ldhio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> ldhio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> ldhio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> ldhio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> ldhio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> ldhio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> ldhio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> ldhio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> ldhio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> ldhio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> ldhio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> ldhio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> ldhio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> ldhio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> ldhio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> ldhio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> ldhio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> ldhio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> ldhio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> ldhio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> ldhio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> ldhio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> ldhio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/ldh.s b/gas/testsuite/gas/nios2/ldh.s new file mode 100644 index 0000000..87040ee --- /dev/null +++ b/gas/testsuite/gas/nios2/ldh.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + ldh r4,0(r0) + ldh r4,4(r0) + ldh r4,0x7ffc(r0) + ldh r4,-0x8000(r0) + ldh r4,0(r5) + ldh r4,4(r5) + ldh r4,0x7ffc(r5) + ldh r4,-0x8000(r5) + ldh r4,data_label(r0) + ldh r4,big_external_data_label(r0) + ldh r4,small_external_data_label(r0) + ldh r4,big_external_common(r0) + ldh r4,small_external_common(r0) + ldh r4,big_local_common(r0) + ldh r4,small_local_common(r0) + ldh r4,data_label+4(r0) + ldh r4,big_external_data_label+4(r0) + ldh r4,small_external_data_label+4(r0) + ldh r4,big_external_common+4(r0) + ldh r4,small_external_common+4(r0) + ldh r4,big_local_common+4(r0) + ldh r4,small_local_common+4(r0) + ldh r4,data_label-0x8000(r0) + ldh r4,big_external_data_label-0x8000(r0) + ldh r4,small_external_data_label-0x8000(r0) + ldh r4,big_external_common-0x8000(r0) + ldh r4,small_external_common-0x8000(r0) + ldh r4,big_local_common-0x8000(r0) + ldh r4,small_local_common-0x8000(r0) + ldh r4,data_label+0x10000(r0) + ldh r4,data_label(r5) + ldh r4,big_external_data_label(r5) + ldh r4,small_external_data_label(r5) + ldh r4,big_external_common(r5) + ldh r4,small_external_common(r5) + ldh r4,big_local_common(r5) + ldh r4,small_local_common(r5) + ldh r4,data_label+4(r5) + ldh r4,big_external_data_label+4(r5) + ldh r4,small_external_data_label+4(r5) + ldh r4,big_external_common+4(r5) + ldh r4,small_external_common+4(r5) + ldh r4,big_local_common+4(r5) + ldh r4,small_local_common+4(r5) + ldh r4,data_label-0x8000(r5) + ldh r4,big_external_data_label-0x8000(r5) + ldh r4,small_external_data_label-0x8000(r5) + ldh r4,big_external_common-0x8000(r5) + ldh r4,small_external_common-0x8000(r5) + ldh r4,big_local_common-0x8000(r5) + ldh r4,small_local_common-0x8000(r5) + + ldhio r4,0(r0) + ldhio r4,4(r0) + ldhio r4,0x7ffc(r0) + ldhio r4,-0x8000(r0) + ldhio r4,0(r5) + ldhio r4,4(r5) + ldhio r4,0x7ffc(r5) + ldhio r4,-0x8000(r5) + ldhio r4,data_label(r0) + ldhio r4,big_external_data_label(r0) + ldhio r4,small_external_data_label(r0) + ldhio r4,big_external_common(r0) + ldhio r4,small_external_common(r0) + ldhio r4,big_local_common(r0) + ldhio r4,small_local_common(r0) + ldhio r4,data_label+4(r0) + ldhio r4,big_external_data_label+4(r0) + ldhio r4,small_external_data_label+4(r0) + ldhio r4,big_external_common+4(r0) + ldhio r4,small_external_common+4(r0) + ldhio r4,big_local_common+4(r0) + ldhio r4,small_local_common+4(r0) + ldhio r4,data_label-0x8000(r0) + ldhio r4,big_external_data_label-0x8000(r0) + ldhio r4,small_external_data_label-0x8000(r0) + ldhio r4,big_external_common-0x8000(r0) + ldhio r4,small_external_common-0x8000(r0) + ldhio r4,big_local_common-0x8000(r0) + ldhio r4,small_local_common-0x8000(r0) + ldhio r4,data_label+0x10000(r0) + ldhio r4,data_label(r5) + ldhio r4,big_external_data_label(r5) + ldhio r4,small_external_data_label(r5) + ldhio r4,big_external_common(r5) + ldhio r4,small_external_common(r5) + ldhio r4,big_local_common(r5) + ldhio r4,small_local_common(r5) + ldhio r4,data_label+4(r5) + ldhio r4,big_external_data_label+4(r5) + ldhio r4,small_external_data_label+4(r5) + ldhio r4,big_external_common+4(r5) + ldhio r4,small_external_common+4(r5) + ldhio r4,big_local_common+4(r5) + ldhio r4,small_local_common+4(r5) + ldhio r4,data_label-0x8000(r5) + ldhio r4,big_external_data_label-0x8000(r5) + ldhio r4,small_external_data_label-0x8000(r5) + ldhio r4,big_external_common-0x8000(r5) + ldhio r4,small_external_common-0x8000(r5) + ldhio r4,big_local_common-0x8000(r5) + ldhio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/ldw.d b/gas/testsuite/gas/nios2/ldw.d new file mode 100644 index 0000000..dc2571e --- /dev/null +++ b/gas/testsuite/gas/nios2/ldw.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 ldw + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> ldw r4,0\(zero\) +0+0004 <[^>]*> ldw r4,4\(zero\) +0+0008 <[^>]*> ldw r4,32764\(zero\) +0+000c <[^>]*> ldw r4,-32768\(zero\) +0+0010 <[^>]*> ldw r4,0\(r5\) +0+0014 <[^>]*> ldw r4,4\(r5\) +0+0018 <[^>]*> ldw r4,32764\(r5\) +0+001c <[^>]*> ldw r4,-32768\(r5\) +0+0020 <[^>]*> ldw r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> ldw r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> ldw r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> ldw r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> ldw r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> ldw r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> ldw r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> ldw r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> ldw r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> ldw r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> ldw r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> ldw r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> ldw r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> ldw r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> ldw r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> ldw r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> ldw r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> ldw r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> ldw r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> ldw r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> ldw r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> ldw r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> ldw r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> ldw r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> ldw r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> ldw r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> ldw r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> ldw r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> ldw r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> ldw r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> ldw r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> ldw r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> ldw r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> ldw r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> ldw r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> ldw r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> ldw r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> ldw r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> ldw r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> ldw r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> ldw r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> ldw r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> ldw r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> ldwio r4,0\(zero\) +0+00d0 <[^>]*> ldwio r4,4\(zero\) +0+00d4 <[^>]*> ldwio r4,32764\(zero\) +0+00d8 <[^>]*> ldwio r4,-32768\(zero\) +0+00dc <[^>]*> ldwio r4,0\(r5\) +0+00e0 <[^>]*> ldwio r4,4\(r5\) +0+00e4 <[^>]*> ldwio r4,32764\(r5\) +0+00e8 <[^>]*> ldwio r4,-32768\(r5\) +0+00ec <[^>]*> ldwio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> ldwio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> ldwio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> ldwio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> ldwio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> ldwio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> ldwio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> ldwio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> ldwio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> ldwio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> ldwio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> ldwio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> ldwio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> ldwio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> ldwio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> ldwio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> ldwio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> ldwio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> ldwio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> ldwio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> ldwio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> ldwio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> ldwio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> ldwio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> ldwio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> ldwio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> ldwio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> ldwio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> ldwio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> ldwio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> ldwio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> ldwio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> ldwio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> ldwio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> ldwio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> ldwio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> ldwio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> ldwio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> ldwio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> ldwio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> ldwio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> ldwio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> ldwio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/ldw.s b/gas/testsuite/gas/nios2/ldw.s new file mode 100644 index 0000000..cf6de19 --- /dev/null +++ b/gas/testsuite/gas/nios2/ldw.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + ldw r4,0(r0) + ldw r4,4(r0) + ldw r4,0x7ffc(r0) + ldw r4,-0x8000(r0) + ldw r4,0(r5) + ldw r4,4(r5) + ldw r4,0x7ffc(r5) + ldw r4,-0x8000(r5) + ldw r4,data_label(r0) + ldw r4,big_external_data_label(r0) + ldw r4,small_external_data_label(r0) + ldw r4,big_external_common(r0) + ldw r4,small_external_common(r0) + ldw r4,big_local_common(r0) + ldw r4,small_local_common(r0) + ldw r4,data_label+4(r0) + ldw r4,big_external_data_label+4(r0) + ldw r4,small_external_data_label+4(r0) + ldw r4,big_external_common+4(r0) + ldw r4,small_external_common+4(r0) + ldw r4,big_local_common+4(r0) + ldw r4,small_local_common+4(r0) + ldw r4,data_label-0x8000(r0) + ldw r4,big_external_data_label-0x8000(r0) + ldw r4,small_external_data_label-0x8000(r0) + ldw r4,big_external_common-0x8000(r0) + ldw r4,small_external_common-0x8000(r0) + ldw r4,big_local_common-0x8000(r0) + ldw r4,small_local_common-0x8000(r0) + ldw r4,data_label+0x10000(r0) + ldw r4,data_label(r5) + ldw r4,big_external_data_label(r5) + ldw r4,small_external_data_label(r5) + ldw r4,big_external_common(r5) + ldw r4,small_external_common(r5) + ldw r4,big_local_common(r5) + ldw r4,small_local_common(r5) + ldw r4,data_label+4(r5) + ldw r4,big_external_data_label+4(r5) + ldw r4,small_external_data_label+4(r5) + ldw r4,big_external_common+4(r5) + ldw r4,small_external_common+4(r5) + ldw r4,big_local_common+4(r5) + ldw r4,small_local_common+4(r5) + ldw r4,data_label-0x8000(r5) + ldw r4,big_external_data_label-0x8000(r5) + ldw r4,small_external_data_label-0x8000(r5) + ldw r4,big_external_common-0x8000(r5) + ldw r4,small_external_common-0x8000(r5) + ldw r4,big_local_common-0x8000(r5) + ldw r4,small_local_common-0x8000(r5) + + ldwio r4,0(r0) + ldwio r4,4(r0) + ldwio r4,0x7ffc(r0) + ldwio r4,-0x8000(r0) + ldwio r4,0(r5) + ldwio r4,4(r5) + ldwio r4,0x7ffc(r5) + ldwio r4,-0x8000(r5) + ldwio r4,data_label(r0) + ldwio r4,big_external_data_label(r0) + ldwio r4,small_external_data_label(r0) + ldwio r4,big_external_common(r0) + ldwio r4,small_external_common(r0) + ldwio r4,big_local_common(r0) + ldwio r4,small_local_common(r0) + ldwio r4,data_label+4(r0) + ldwio r4,big_external_data_label+4(r0) + ldwio r4,small_external_data_label+4(r0) + ldwio r4,big_external_common+4(r0) + ldwio r4,small_external_common+4(r0) + ldwio r4,big_local_common+4(r0) + ldwio r4,small_local_common+4(r0) + ldwio r4,data_label-0x8000(r0) + ldwio r4,big_external_data_label-0x8000(r0) + ldwio r4,small_external_data_label-0x8000(r0) + ldwio r4,big_external_common-0x8000(r0) + ldwio r4,small_external_common-0x8000(r0) + ldwio r4,big_local_common-0x8000(r0) + ldwio r4,small_local_common-0x8000(r0) + ldwio r4,data_label+0x10000(r0) + ldwio r4,data_label(r5) + ldwio r4,big_external_data_label(r5) + ldwio r4,small_external_data_label(r5) + ldwio r4,big_external_common(r5) + ldwio r4,small_external_common(r5) + ldwio r4,big_local_common(r5) + ldwio r4,small_local_common(r5) + ldwio r4,data_label+4(r5) + ldwio r4,big_external_data_label+4(r5) + ldwio r4,small_external_data_label+4(r5) + ldwio r4,big_external_common+4(r5) + ldwio r4,small_external_common+4(r5) + ldwio r4,big_local_common+4(r5) + ldwio r4,small_local_common+4(r5) + ldwio r4,data_label-0x8000(r5) + ldwio r4,big_external_data_label-0x8000(r5) + ldwio r4,small_external_data_label-0x8000(r5) + ldwio r4,big_external_common-0x8000(r5) + ldwio r4,small_external_common-0x8000(r5) + ldwio r4,big_local_common-0x8000(r5) + ldwio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/lineseparator.d b/gas/testsuite/gas/nios2/lineseparator.d new file mode 100644 index 0000000..09c66ea --- /dev/null +++ b/gas/testsuite/gas/nios2/lineseparator.d @@ -0,0 +1,10 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 lineseparator + +# Test the add instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0x0+0000 mov r5,r4 +0x0+0004 mov r4,r5 diff --git a/gas/testsuite/gas/nios2/lineseparator.s b/gas/testsuite/gas/nios2/lineseparator.s new file mode 100644 index 0000000..d16efc3 --- /dev/null +++ b/gas/testsuite/gas/nios2/lineseparator.s @@ -0,0 +1,4 @@ +mov r5, r4 ; mov r4, r5 + + + diff --git a/gas/testsuite/gas/nios2/mov.d b/gas/testsuite/gas/nios2/mov.d new file mode 100644 index 0000000..13bf6db --- /dev/null +++ b/gas/testsuite/gas/nios2/mov.d @@ -0,0 +1,11 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 mov + +# Test the mov instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> movz \$4,\$5,\$6 +0+0004 <[^>]*> movnz \$4,\$5,\$6 + diff --git a/gas/testsuite/gas/nios2/mov.s b/gas/testsuite/gas/nios2/mov.s new file mode 100644 index 0000000..a66aaeb --- /dev/null +++ b/gas/testsuite/gas/nios2/mov.s @@ -0,0 +1,5 @@ +# Source file used to test the movz and movnz instructions + +foo: + movz $4,$5,$6 + movnz $4,$5,$6 diff --git a/gas/testsuite/gas/nios2/movi.d b/gas/testsuite/gas/nios2/movi.d new file mode 100644 index 0000000..9e35c7b --- /dev/null +++ b/gas/testsuite/gas/nios2/movi.d @@ -0,0 +1,13 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 movi + +# Test implicit conversion of movi/movhi etc +.*: file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> movi r2,32 +0+0004 <[^>]*> movhi r2,8192 +0+0008 <[^>]*> movhi r2,65535 +0+000c <[^>]*> orhi r2,r5,65535 +0+0010 <[^>]*> xorhi r2,r10,65535 +0+0014 <[^>]*> andhi r2,r15,65535 diff --git a/gas/testsuite/gas/nios2/movi.s b/gas/testsuite/gas/nios2/movi.s new file mode 100644 index 0000000..07d9fed --- /dev/null +++ b/gas/testsuite/gas/nios2/movi.s @@ -0,0 +1,21 @@ +# Source file used to test silent conversion of +# movi to orhi etc + +foo: +# this doesn't get converted +movi r2, 0x20 + +# this does +movi r2, 0x20000000 + +# addi should convert only if the source register is r0 +addi r2, r0, 0xffff0000 +# but we can't test for non-conversion because the value would +# be out of range + +# logical ops should convert for any register +ori r2, r5, 0xffff0000 +xori r2, r10, 0xffff0000 +andi r2, r15, 0xffff0000 + + diff --git a/gas/testsuite/gas/nios2/movia.d b/gas/testsuite/gas/nios2/movia.d new file mode 100644 index 0000000..c255ace --- /dev/null +++ b/gas/testsuite/gas/nios2/movia.d @@ -0,0 +1,18 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 movia + +# Test the movia instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> movhi r2,32897 +0+0004 <[^>]*> addi r2,r2,-32640 +0+0008 <[^>]*> movhi r3,0 + 8: R_NIOS2_HIADJ16 sym-0x80000000 +0+000c <[^>]*> addi r3,r3,0 + c: R_NIOS2_LO16 sym-0x80000000 +0+0010 <[^>]*> movhi r4,0 + 10: R_NIOS2_HIADJ16 sym-0x7fffffff +0+0014 <[^>]*> addi r4,r4,0 + 14: R_NIOS2_LO16 sym-0x7fffffff diff --git a/gas/testsuite/gas/nios2/movia.s b/gas/testsuite/gas/nios2/movia.s new file mode 100644 index 0000000..fe1d56c --- /dev/null +++ b/gas/testsuite/gas/nios2/movia.s @@ -0,0 +1,6 @@ +# Test program for movia reg, immed32 macro + +foo: + movia r2, 0x80808080 + movia r3, sym + 0x80000000 + movia r4, sym - 0x7fffffff diff --git a/gas/testsuite/gas/nios2/mul.d b/gas/testsuite/gas/nios2/mul.d new file mode 100644 index 0000000..79e86d1 --- /dev/null +++ b/gas/testsuite/gas/nios2/mul.d @@ -0,0 +1,19 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 mul + +# Test the mul macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> mul r4,r5,r6 +0+0004 <[^>]*> muli r4,r5,0 +0+0008 <[^>]*> muli r4,r5,1 +0+000c <[^>]*> muli r4,r5,-32768 +0+0010 <[^>]*> muli r4,r5,32767 +0+0014 <[^>]*> muli r4,r5,0 +[ ]*14: R_NIOS2_S16 undefined_symbol +0+0018 <[^>]*> muli r4,r5,16448 +0+001c <[^>]*> mulxss r4,r5,r6 +0+0020 <[^>]*> mulxsu r4,r5,r6 +0+0024 <[^>]*> mulxuu r4,r5,r6 diff --git a/gas/testsuite/gas/nios2/mul.s b/gas/testsuite/gas/nios2/mul.s new file mode 100644 index 0000000..3e47bc7 --- /dev/null +++ b/gas/testsuite/gas/nios2/mul.s @@ -0,0 +1,15 @@ +# Source file used to test the mul macro. + +foo: + mul r4,r5,r6 + muli r4,r5,0 + muli r4,r5,1 + muli r4,r5,-0x8000 + muli r4,r5,0x7fff + muli r4,r5,undefined_symbol + muli r4,r5,defined_symbol + mulxss r4,r5,r6 + mulxsu r4,r5,r6 + mulxuu r4,r5,r6 +.data +.set defined_symbol, 0x4040 diff --git a/gas/testsuite/gas/nios2/nios2.exp b/gas/testsuite/gas/nios2/nios2.exp new file mode 100644 index 0000000..9390e8b --- /dev/null +++ b/gas/testsuite/gas/nios2/nios2.exp @@ -0,0 +1,75 @@ +# +# Some generic Nios II tests +# + +proc run_list_test { name } { + global srcdir subdir + set testname "NIOS2 $name" + set file $srcdir/$subdir/$name + gas_run ${name}.s "" ">&dump.out" + if { [regexp_diff "dump.out" "${file}.l"] } then { + fail $testname + verbose "output is [file_contents "dump.out"]" 2 + return + } + pass $testname +} + +if { [istarget nios2-*-*] } then { + + run_dump_test "add" + run_dump_test "and" + run_dump_test "align_fill" + run_dump_test "align_text" + + run_dump_test "branch" + + run_dump_test "break" + run_dump_test "bret" + run_dump_test "cache" + + run_dump_test "call" + run_dump_test "call26" + + run_dump_test "cmp" + + run_dump_test "jmp" + run_dump_test "ldw" + run_dump_test "ldh" + run_dump_test "ldb" + + run_dump_test "flushda" + + run_dump_test "mul" + + run_dump_test "nor" + run_dump_test "or" + + run_dump_test "ctl" + run_dump_test "ret" + run_dump_test "rotate" + + run_dump_test "stw" + run_dump_test "sth" + run_dump_test "stb" + + run_dump_test "sub" + run_dump_test "sync" + run_dump_test "trap" + run_dump_test "tret" + + run_dump_test "custom" + run_dump_test "xor" + run_dump_test "movia" + + run_dump_test "complex" + run_dump_test "comments" + run_dump_test "etbt" + run_dump_test "lineseparator" + run_dump_test "movi" + + run_list_test "illegal" + run_list_test "warn_nobreak" + run_list_test "warn_noat" + +} diff --git a/gas/testsuite/gas/nios2/nor.d b/gas/testsuite/gas/nios2/nor.d new file mode 100644 index 0000000..fab8e69 --- /dev/null +++ b/gas/testsuite/gas/nios2/nor.d @@ -0,0 +1,9 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 nor + +# Test the nor instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> nor r6,r8,r10 diff --git a/gas/testsuite/gas/nios2/nor.s b/gas/testsuite/gas/nios2/nor.s new file mode 100644 index 0000000..da78254 --- /dev/null +++ b/gas/testsuite/gas/nios2/nor.s @@ -0,0 +1,5 @@ +# Source file used to test the nor instruction + +foo: + nor r6,r8,r10 + diff --git a/gas/testsuite/gas/nios2/or.d b/gas/testsuite/gas/nios2/or.d new file mode 100644 index 0000000..e5035bc --- /dev/null +++ b/gas/testsuite/gas/nios2/or.d @@ -0,0 +1,11 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 or + +# Test the nor instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> or r6,r8,r10 +0+0004 <[^>]*> orhi r6,r7,65535 +0+0008 <[^>]*> ori r6,r7,65535 diff --git a/gas/testsuite/gas/nios2/or.s b/gas/testsuite/gas/nios2/or.s new file mode 100644 index 0000000..675df17 --- /dev/null +++ b/gas/testsuite/gas/nios2/or.s @@ -0,0 +1,7 @@ +# Source file used to test the nor instruction + +foo: + or r6,r8,r10 + orhi r6,r7,0xffff + ori r6,r7,0xffff + diff --git a/gas/testsuite/gas/nios2/ret.d b/gas/testsuite/gas/nios2/ret.d new file mode 100644 index 0000000..b071931 --- /dev/null +++ b/gas/testsuite/gas/nios2/ret.d @@ -0,0 +1,8 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 ret + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> ret + diff --git a/gas/testsuite/gas/nios2/ret.s b/gas/testsuite/gas/nios2/ret.s new file mode 100644 index 0000000..69b76bc --- /dev/null +++ b/gas/testsuite/gas/nios2/ret.s @@ -0,0 +1,5 @@ +# Source file used to test the ret instructions +foo: + ret + + diff --git a/gas/testsuite/gas/nios2/rol.d b/gas/testsuite/gas/nios2/rol.d new file mode 100644 index 0000000..2128dd5 --- /dev/null +++ b/gas/testsuite/gas/nios2/rol.d @@ -0,0 +1,40 @@ +#objdump: -dr --prefix-addresses -mmips:3000 +#as: -march=r3000 -mtune=r3000 +#name: MIPS R3000 rol + +# Test the rol and ror macros. + +.*: +file format .*mips.* + +Disassembly of section .text: +0+0000 <[^>]*> negu at,a1 +0+0004 <[^>]*> srlv at,a0,at +0+0008 <[^>]*> sllv a0,a0,a1 +0+000c <[^>]*> or a0,a0,at +0+0010 <[^>]*> negu at,a2 +0+0014 <[^>]*> srlv at,a1,at +0+0018 <[^>]*> sllv a0,a1,a2 +0+001c <[^>]*> or a0,a0,at +0+0020 <[^>]*> sll at,a0,0x1 +0+0024 <[^>]*> srl a0,a0,0x1f +0+0028 <[^>]*> or a0,a0,at +0+002c <[^>]*> sll at,a1,0x1 +0+0030 <[^>]*> srl a0,a1,0x1f +0+0034 <[^>]*> or a0,a0,at +0+0038 <[^>]*> srl a0,a1,0x0 +0+003c <[^>]*> negu at,a1 +0+0040 <[^>]*> sllv at,a0,at +0+0044 <[^>]*> srlv a0,a0,a1 +0+0048 <[^>]*> or a0,a0,at +0+004c <[^>]*> negu at,a2 +0+0050 <[^>]*> sllv at,a1,at +0+0054 <[^>]*> srlv a0,a1,a2 +0+0058 <[^>]*> or a0,a0,at +0+005c <[^>]*> srl at,a0,0x1 +0+0060 <[^>]*> sll a0,a0,0x1f +0+0064 <[^>]*> or a0,a0,at +0+0068 <[^>]*> srl at,a1,0x1 +0+006c <[^>]*> sll a0,a1,0x1f +0+0070 <[^>]*> or a0,a0,at +0+0074 <[^>]*> srl a0,a1,0x0 + ... diff --git a/gas/testsuite/gas/nios2/rol.s b/gas/testsuite/gas/nios2/rol.s new file mode 100644 index 0000000..988d702 --- /dev/null +++ b/gas/testsuite/gas/nios2/rol.s @@ -0,0 +1,15 @@ +# Source file used to test the rol and ror macros. + +foo: + rol $4,$5 + rol $4,$5,$6 + rol $4,1 + rol $4,$5,1 + rol $4,$5,0 + + ror $4,$5 + ror $4,$5,$6 + ror $4,1 + ror $4,$5,1 + ror $4,$5,0 + .space 8 diff --git a/gas/testsuite/gas/nios2/rotate.d b/gas/testsuite/gas/nios2/rotate.d new file mode 100644 index 0000000..0f54f43 --- /dev/null +++ b/gas/testsuite/gas/nios2/rotate.d @@ -0,0 +1,17 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 rotate + +# Test the and macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> rol r4,r4,r4 +0+0004 <[^>]*> roli r4,r4,31 +0+0008 <[^>]*> ror r4,r4,r4 +0+000c <[^>]*> sll r4,r4,r4 +0+0010 <[^>]*> slli r4,r4,24 +0+0014 <[^>]*> sra r4,r4,r4 +0+0018 <[^>]*> srai r4,r4,10 +0+001c <[^>]*> srl r4,r4,r4 +0+0020 <[^>]*> srli r4,r4,5 diff --git a/gas/testsuite/gas/nios2/rotate.s b/gas/testsuite/gas/nios2/rotate.s new file mode 100644 index 0000000..a960e19 --- /dev/null +++ b/gas/testsuite/gas/nios2/rotate.s @@ -0,0 +1,13 @@ +# test Nios II rotate instructions + +.text +foo: + rol r4,r4,r4 + roli r4,r4,31 + ror r4,r4,r4 + sll r4,r4,r4 + slli r4,r4,24 + sra r4,r4,r4 + srai r4,r4,10 + srl r4,r4,r4 + srli r4,r4,5 diff --git a/gas/testsuite/gas/nios2/stb.d b/gas/testsuite/gas/nios2/stb.d new file mode 100644 index 0000000..e3b4818 --- /dev/null +++ b/gas/testsuite/gas/nios2/stb.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 stb + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> stb r4,0\(zero\) +0+0004 <[^>]*> stb r4,4\(zero\) +0+0008 <[^>]*> stb r4,32764\(zero\) +0+000c <[^>]*> stb r4,-32768\(zero\) +0+0010 <[^>]*> stb r4,0\(r5\) +0+0014 <[^>]*> stb r4,4\(r5\) +0+0018 <[^>]*> stb r4,32764\(r5\) +0+001c <[^>]*> stb r4,-32768\(r5\) +0+0020 <[^>]*> stb r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> stb r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> stb r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> stb r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> stb r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> stb r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> stb r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> stb r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> stb r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> stb r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> stb r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> stb r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> stb r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> stb r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> stb r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> stb r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> stb r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> stb r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> stb r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> stb r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> stb r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> stb r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> stb r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> stb r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> stb r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> stb r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> stb r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> stb r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> stb r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> stb r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> stb r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> stb r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> stb r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> stb r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> stb r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> stb r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> stb r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> stb r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> stb r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> stb r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> stb r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> stb r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> stb r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> stbio r4,0\(zero\) +0+00d0 <[^>]*> stbio r4,4\(zero\) +0+00d4 <[^>]*> stbio r4,32764\(zero\) +0+00d8 <[^>]*> stbio r4,-32768\(zero\) +0+00dc <[^>]*> stbio r4,0\(r5\) +0+00e0 <[^>]*> stbio r4,4\(r5\) +0+00e4 <[^>]*> stbio r4,32764\(r5\) +0+00e8 <[^>]*> stbio r4,-32768\(r5\) +0+00ec <[^>]*> stbio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> stbio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> stbio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> stbio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> stbio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> stbio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> stbio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> stbio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> stbio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> stbio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> stbio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> stbio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> stbio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> stbio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> stbio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> stbio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> stbio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> stbio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> stbio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> stbio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> stbio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> stbio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> stbio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> stbio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> stbio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> stbio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> stbio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> stbio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> stbio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> stbio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> stbio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> stbio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> stbio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> stbio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> stbio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> stbio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> stbio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> stbio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> stbio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> stbio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> stbio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> stbio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> stbio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/stb.s b/gas/testsuite/gas/nios2/stb.s new file mode 100644 index 0000000..8078e94 --- /dev/null +++ b/gas/testsuite/gas/nios2/stb.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + stb r4,0(r0) + stb r4,4(r0) + stb r4,0x7ffc(r0) + stb r4,-0x8000(r0) + stb r4,0(r5) + stb r4,4(r5) + stb r4,0x7ffc(r5) + stb r4,-0x8000(r5) + stb r4,data_label(r0) + stb r4,big_external_data_label(r0) + stb r4,small_external_data_label(r0) + stb r4,big_external_common(r0) + stb r4,small_external_common(r0) + stb r4,big_local_common(r0) + stb r4,small_local_common(r0) + stb r4,data_label+4(r0) + stb r4,big_external_data_label+4(r0) + stb r4,small_external_data_label+4(r0) + stb r4,big_external_common+4(r0) + stb r4,small_external_common+4(r0) + stb r4,big_local_common+4(r0) + stb r4,small_local_common+4(r0) + stb r4,data_label-0x8000(r0) + stb r4,big_external_data_label-0x8000(r0) + stb r4,small_external_data_label-0x8000(r0) + stb r4,big_external_common-0x8000(r0) + stb r4,small_external_common-0x8000(r0) + stb r4,big_local_common-0x8000(r0) + stb r4,small_local_common-0x8000(r0) + stb r4,data_label+0x10000(r0) + stb r4,data_label(r5) + stb r4,big_external_data_label(r5) + stb r4,small_external_data_label(r5) + stb r4,big_external_common(r5) + stb r4,small_external_common(r5) + stb r4,big_local_common(r5) + stb r4,small_local_common(r5) + stb r4,data_label+4(r5) + stb r4,big_external_data_label+4(r5) + stb r4,small_external_data_label+4(r5) + stb r4,big_external_common+4(r5) + stb r4,small_external_common+4(r5) + stb r4,big_local_common+4(r5) + stb r4,small_local_common+4(r5) + stb r4,data_label-0x8000(r5) + stb r4,big_external_data_label-0x8000(r5) + stb r4,small_external_data_label-0x8000(r5) + stb r4,big_external_common-0x8000(r5) + stb r4,small_external_common-0x8000(r5) + stb r4,big_local_common-0x8000(r5) + stb r4,small_local_common-0x8000(r5) + + stbio r4,0(r0) + stbio r4,4(r0) + stbio r4,0x7ffc(r0) + stbio r4,-0x8000(r0) + stbio r4,0(r5) + stbio r4,4(r5) + stbio r4,0x7ffc(r5) + stbio r4,-0x8000(r5) + stbio r4,data_label(r0) + stbio r4,big_external_data_label(r0) + stbio r4,small_external_data_label(r0) + stbio r4,big_external_common(r0) + stbio r4,small_external_common(r0) + stbio r4,big_local_common(r0) + stbio r4,small_local_common(r0) + stbio r4,data_label+4(r0) + stbio r4,big_external_data_label+4(r0) + stbio r4,small_external_data_label+4(r0) + stbio r4,big_external_common+4(r0) + stbio r4,small_external_common+4(r0) + stbio r4,big_local_common+4(r0) + stbio r4,small_local_common+4(r0) + stbio r4,data_label-0x8000(r0) + stbio r4,big_external_data_label-0x8000(r0) + stbio r4,small_external_data_label-0x8000(r0) + stbio r4,big_external_common-0x8000(r0) + stbio r4,small_external_common-0x8000(r0) + stbio r4,big_local_common-0x8000(r0) + stbio r4,small_local_common-0x8000(r0) + stbio r4,data_label+0x10000(r0) + stbio r4,data_label(r5) + stbio r4,big_external_data_label(r5) + stbio r4,small_external_data_label(r5) + stbio r4,big_external_common(r5) + stbio r4,small_external_common(r5) + stbio r4,big_local_common(r5) + stbio r4,small_local_common(r5) + stbio r4,data_label+4(r5) + stbio r4,big_external_data_label+4(r5) + stbio r4,small_external_data_label+4(r5) + stbio r4,big_external_common+4(r5) + stbio r4,small_external_common+4(r5) + stbio r4,big_local_common+4(r5) + stbio r4,small_local_common+4(r5) + stbio r4,data_label-0x8000(r5) + stbio r4,big_external_data_label-0x8000(r5) + stbio r4,small_external_data_label-0x8000(r5) + stbio r4,big_external_common-0x8000(r5) + stbio r4,small_external_common-0x8000(r5) + stbio r4,big_local_common-0x8000(r5) + stbio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/sth.d b/gas/testsuite/gas/nios2/sth.d new file mode 100644 index 0000000..76d58d4 --- /dev/null +++ b/gas/testsuite/gas/nios2/sth.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 sth + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> sth r4,0\(zero\) +0+0004 <[^>]*> sth r4,4\(zero\) +0+0008 <[^>]*> sth r4,32764\(zero\) +0+000c <[^>]*> sth r4,-32768\(zero\) +0+0010 <[^>]*> sth r4,0\(r5\) +0+0014 <[^>]*> sth r4,4\(r5\) +0+0018 <[^>]*> sth r4,32764\(r5\) +0+001c <[^>]*> sth r4,-32768\(r5\) +0+0020 <[^>]*> sth r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> sth r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> sth r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> sth r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> sth r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> sth r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> sth r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> sth r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> sth r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> sth r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> sth r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> sth r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> sth r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> sth r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> sth r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> sth r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> sth r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> sth r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> sth r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> sth r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> sth r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> sth r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> sth r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> sth r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> sth r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> sth r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> sth r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> sth r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> sth r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> sth r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> sth r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> sth r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> sth r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> sth r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> sth r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> sth r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> sth r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> sth r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> sth r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> sth r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> sth r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> sth r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> sth r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> sthio r4,0\(zero\) +0+00d0 <[^>]*> sthio r4,4\(zero\) +0+00d4 <[^>]*> sthio r4,32764\(zero\) +0+00d8 <[^>]*> sthio r4,-32768\(zero\) +0+00dc <[^>]*> sthio r4,0\(r5\) +0+00e0 <[^>]*> sthio r4,4\(r5\) +0+00e4 <[^>]*> sthio r4,32764\(r5\) +0+00e8 <[^>]*> sthio r4,-32768\(r5\) +0+00ec <[^>]*> sthio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> sthio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> sthio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> sthio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> sthio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> sthio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> sthio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> sthio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> sthio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> sthio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> sthio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> sthio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> sthio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> sthio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> sthio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> sthio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> sthio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> sthio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> sthio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> sthio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> sthio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> sthio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> sthio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> sthio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> sthio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> sthio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> sthio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> sthio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> sthio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> sthio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> sthio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> sthio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> sthio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> sthio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> sthio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> sthio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> sthio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> sthio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> sthio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> sthio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> sthio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> sthio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> sthio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/sth.s b/gas/testsuite/gas/nios2/sth.s new file mode 100644 index 0000000..4b9390b --- /dev/null +++ b/gas/testsuite/gas/nios2/sth.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + sth r4,0(r0) + sth r4,4(r0) + sth r4,0x7ffc(r0) + sth r4,-0x8000(r0) + sth r4,0(r5) + sth r4,4(r5) + sth r4,0x7ffc(r5) + sth r4,-0x8000(r5) + sth r4,data_label(r0) + sth r4,big_external_data_label(r0) + sth r4,small_external_data_label(r0) + sth r4,big_external_common(r0) + sth r4,small_external_common(r0) + sth r4,big_local_common(r0) + sth r4,small_local_common(r0) + sth r4,data_label+4(r0) + sth r4,big_external_data_label+4(r0) + sth r4,small_external_data_label+4(r0) + sth r4,big_external_common+4(r0) + sth r4,small_external_common+4(r0) + sth r4,big_local_common+4(r0) + sth r4,small_local_common+4(r0) + sth r4,data_label-0x8000(r0) + sth r4,big_external_data_label-0x8000(r0) + sth r4,small_external_data_label-0x8000(r0) + sth r4,big_external_common-0x8000(r0) + sth r4,small_external_common-0x8000(r0) + sth r4,big_local_common-0x8000(r0) + sth r4,small_local_common-0x8000(r0) + sth r4,data_label+0x10000(r0) + sth r4,data_label(r5) + sth r4,big_external_data_label(r5) + sth r4,small_external_data_label(r5) + sth r4,big_external_common(r5) + sth r4,small_external_common(r5) + sth r4,big_local_common(r5) + sth r4,small_local_common(r5) + sth r4,data_label+4(r5) + sth r4,big_external_data_label+4(r5) + sth r4,small_external_data_label+4(r5) + sth r4,big_external_common+4(r5) + sth r4,small_external_common+4(r5) + sth r4,big_local_common+4(r5) + sth r4,small_local_common+4(r5) + sth r4,data_label-0x8000(r5) + sth r4,big_external_data_label-0x8000(r5) + sth r4,small_external_data_label-0x8000(r5) + sth r4,big_external_common-0x8000(r5) + sth r4,small_external_common-0x8000(r5) + sth r4,big_local_common-0x8000(r5) + sth r4,small_local_common-0x8000(r5) + + sthio r4,0(r0) + sthio r4,4(r0) + sthio r4,0x7ffc(r0) + sthio r4,-0x8000(r0) + sthio r4,0(r5) + sthio r4,4(r5) + sthio r4,0x7ffc(r5) + sthio r4,-0x8000(r5) + sthio r4,data_label(r0) + sthio r4,big_external_data_label(r0) + sthio r4,small_external_data_label(r0) + sthio r4,big_external_common(r0) + sthio r4,small_external_common(r0) + sthio r4,big_local_common(r0) + sthio r4,small_local_common(r0) + sthio r4,data_label+4(r0) + sthio r4,big_external_data_label+4(r0) + sthio r4,small_external_data_label+4(r0) + sthio r4,big_external_common+4(r0) + sthio r4,small_external_common+4(r0) + sthio r4,big_local_common+4(r0) + sthio r4,small_local_common+4(r0) + sthio r4,data_label-0x8000(r0) + sthio r4,big_external_data_label-0x8000(r0) + sthio r4,small_external_data_label-0x8000(r0) + sthio r4,big_external_common-0x8000(r0) + sthio r4,small_external_common-0x8000(r0) + sthio r4,big_local_common-0x8000(r0) + sthio r4,small_local_common-0x8000(r0) + sthio r4,data_label+0x10000(r0) + sthio r4,data_label(r5) + sthio r4,big_external_data_label(r5) + sthio r4,small_external_data_label(r5) + sthio r4,big_external_common(r5) + sthio r4,small_external_common(r5) + sthio r4,big_local_common(r5) + sthio r4,small_local_common(r5) + sthio r4,data_label+4(r5) + sthio r4,big_external_data_label+4(r5) + sthio r4,small_external_data_label+4(r5) + sthio r4,big_external_common+4(r5) + sthio r4,small_external_common+4(r5) + sthio r4,big_local_common+4(r5) + sthio r4,small_local_common+4(r5) + sthio r4,data_label-0x8000(r5) + sthio r4,big_external_data_label-0x8000(r5) + sthio r4,small_external_data_label-0x8000(r5) + sthio r4,big_external_common-0x8000(r5) + sthio r4,small_external_common-0x8000(r5) + sthio r4,big_local_common-0x8000(r5) + sthio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/stw.d b/gas/testsuite/gas/nios2/stw.d new file mode 100644 index 0000000..6dcf4e5 --- /dev/null +++ b/gas/testsuite/gas/nios2/stw.d @@ -0,0 +1,196 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 stw + +# Test the ld instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> stw r4,0\(zero\) +0+0004 <[^>]*> stw r4,4\(zero\) +0+0008 <[^>]*> stw r4,32764\(zero\) +0+000c <[^>]*> stw r4,-32768\(zero\) +0+0010 <[^>]*> stw r4,0\(r5\) +0+0014 <[^>]*> stw r4,4\(r5\) +0+0018 <[^>]*> stw r4,32764\(r5\) +0+001c <[^>]*> stw r4,-32768\(r5\) +0+0020 <[^>]*> stw r4,0\(zero\) +[ ]*20: R_NIOS2_S16 .data +0+0024 <[^>]*> stw r4,0\(zero\) +[ ]*24: R_NIOS2_S16 big_external_data_label +0+0028 <[^>]*> stw r4,0\(zero\) +[ ]*28: R_NIOS2_S16 small_external_data_label +0+002c <[^>]*> stw r4,0\(zero\) +[ ]*2c: R_NIOS2_S16 big_external_common +0+0030 <[^>]*> stw r4,0\(zero\) +[ ]*30: R_NIOS2_S16 small_external_common +0+0034 <[^>]*> stw r4,0\(zero\) +[ ]*34: R_NIOS2_S16 .bss +0+0038 <[^>]*> stw r4,0\(zero\) +[ ]*38: R_NIOS2_S16 .bss\+0x4000 +0+003c <[^>]*> stw r4,0\(zero\) +[ ]*3c: R_NIOS2_S16 .data\+0x4 +0+0040 <[^>]*> stw r4,0\(zero\) +[ ]*40: R_NIOS2_S16 big_external_data_label\+0x4 +0+0044 <[^>]*> stw r4,0\(zero\) +[ ]*44: R_NIOS2_S16 small_external_data_label\+0x4 +0+0048 <[^>]*> stw r4,0\(zero\) +[ ]*48: R_NIOS2_S16 big_external_common\+0x4 +0+004c <[^>]*> stw r4,0\(zero\) +[ ]*4c: R_NIOS2_S16 small_external_common\+0x4 +0+0050 <[^>]*> stw r4,0\(zero\) +[ ]*50: R_NIOS2_S16 .bss\+0x4 +0+0054 <[^>]*> stw r4,0\(zero\) +[ ]*54: R_NIOS2_S16 .bss\+0x4004 +0+0058 <[^>]*> stw r4,0\(zero\) +[ ]*58: R_NIOS2_S16 .data-0x8000 +0+005c <[^>]*> stw r4,0\(zero\) +[ ]*5c: R_NIOS2_S16 big_external_data_label-0x8000 +0+0060 <[^>]*> stw r4,0\(zero\) +[ ]*60: R_NIOS2_S16 small_external_data_label-0x8000 +0+0064 <[^>]*> stw r4,0\(zero\) +[ ]*64: R_NIOS2_S16 big_external_common-0x8000 +0+0068 <[^>]*> stw r4,0\(zero\) +[ ]*68: R_NIOS2_S16 small_external_common-0x8000 +0+006c <[^>]*> stw r4,0\(zero\) +[ ]*6c: R_NIOS2_S16 .bss-0x8000 +0+0070 <[^>]*> stw r4,0\(zero\) +[ ]*70: R_NIOS2_S16 .bss-0x4000 +0+0074 <[^>]*> stw r4,0\(zero\) +[ ]*74: R_NIOS2_S16 .data\+0x10000 +0+0078 <[^>]*> stw r4,0\(r5\) +[ ]*78: R_NIOS2_S16 .data +0+007c <[^>]*> stw r4,0\(r5\) +[ ]*7c: R_NIOS2_S16 big_external_data_label +0+0080 <[^>]*> stw r4,0\(r5\) +[ ]*80: R_NIOS2_S16 small_external_data_label +0+0084 <[^>]*> stw r4,0\(r5\) +[ ]*84: R_NIOS2_S16 big_external_common +0+0088 <[^>]*> stw r4,0\(r5\) +[ ]*88: R_NIOS2_S16 small_external_common +0+008c <[^>]*> stw r4,0\(r5\) +[ ]*8c: R_NIOS2_S16 .bss +0+0090 <[^>]*> stw r4,0\(r5\) +[ ]*90: R_NIOS2_S16 .bss\+0x4000 +0+0094 <[^>]*> stw r4,0\(r5\) +[ ]*94: R_NIOS2_S16 .data\+0x4 +0+0098 <[^>]*> stw r4,0\(r5\) +[ ]*98: R_NIOS2_S16 big_external_data_label\+0x4 +0+009c <[^>]*> stw r4,0\(r5\) +[ ]*9c: R_NIOS2_S16 small_external_data_label\+0x4 +0+00a0 <[^>]*> stw r4,0\(r5\) +[ ]*a0: R_NIOS2_S16 big_external_common\+0x4 +0+00a4 <[^>]*> stw r4,0\(r5\) +[ ]*a4: R_NIOS2_S16 small_external_common\+0x4 +0+00a8 <[^>]*> stw r4,0\(r5\) +[ ]*a8: R_NIOS2_S16 .bss\+0x4 +0+00ac <[^>]*> stw r4,0\(r5\) +[ ]*ac: R_NIOS2_S16 .bss\+0x4004 +0+00b0 <[^>]*> stw r4,0\(r5\) +[ ]*b0: R_NIOS2_S16 .data-0x8000 +0+00b4 <[^>]*> stw r4,0\(r5\) +[ ]*b4: R_NIOS2_S16 big_external_data_label-0x8000 +0+00b8 <[^>]*> stw r4,0\(r5\) +[ ]*b8: R_NIOS2_S16 small_external_data_label-0x8000 +0+00bc <[^>]*> stw r4,0\(r5\) +[ ]*bc: R_NIOS2_S16 big_external_common-0x8000 +0+00c0 <[^>]*> stw r4,0\(r5\) +[ ]*c0: R_NIOS2_S16 small_external_common-0x8000 +0+00c4 <[^>]*> stw r4,0\(r5\) +[ ]*c4: R_NIOS2_S16 .bss-0x8000 +0+00c8 <[^>]*> stw r4,0\(r5\) +[ ]*c8: R_NIOS2_S16 .bss-0x4000 +0+00cc <[^>]*> stwio r4,0\(zero\) +0+00d0 <[^>]*> stwio r4,4\(zero\) +0+00d4 <[^>]*> stwio r4,32764\(zero\) +0+00d8 <[^>]*> stwio r4,-32768\(zero\) +0+00dc <[^>]*> stwio r4,0\(r5\) +0+00e0 <[^>]*> stwio r4,4\(r5\) +0+00e4 <[^>]*> stwio r4,32764\(r5\) +0+00e8 <[^>]*> stwio r4,-32768\(r5\) +0+00ec <[^>]*> stwio r4,0\(zero\) +[ ]*ec: R_NIOS2_S16 .data +0+00f0 <[^>]*> stwio r4,0\(zero\) +[ ]*f0: R_NIOS2_S16 big_external_data_label +0+00f4 <[^>]*> stwio r4,0\(zero\) +[ ]*f4: R_NIOS2_S16 small_external_data_label +0+00f8 <[^>]*> stwio r4,0\(zero\) +[ ]*f8: R_NIOS2_S16 big_external_common +0+00fc <[^>]*> stwio r4,0\(zero\) +[ ]*fc: R_NIOS2_S16 small_external_common +0+0100 <[^>]*> stwio r4,0\(zero\) +[ ]*100: R_NIOS2_S16 .bss +0+0104 <[^>]*> stwio r4,0\(zero\) +[ ]*104: R_NIOS2_S16 .bss\+0x4000 +0+0108 <[^>]*> stwio r4,0\(zero\) +[ ]*108: R_NIOS2_S16 .data\+0x4 +0+010c <[^>]*> stwio r4,0\(zero\) +[ ]*10c: R_NIOS2_S16 big_external_data_label\+0x4 +0+0110 <[^>]*> stwio r4,0\(zero\) +[ ]*110: R_NIOS2_S16 small_external_data_label\+0x4 +0+0114 <[^>]*> stwio r4,0\(zero\) +[ ]*114: R_NIOS2_S16 big_external_common\+0x4 +0+0118 <[^>]*> stwio r4,0\(zero\) +[ ]*118: R_NIOS2_S16 small_external_common\+0x4 +0+011c <[^>]*> stwio r4,0\(zero\) +[ ]*11c: R_NIOS2_S16 .bss\+0x4 +0+0120 <[^>]*> stwio r4,0\(zero\) +[ ]*120: R_NIOS2_S16 .bss\+0x4004 +0+0124 <[^>]*> stwio r4,0\(zero\) +[ ]*124: R_NIOS2_S16 .data-0x8000 +0+0128 <[^>]*> stwio r4,0\(zero\) +[ ]*128: R_NIOS2_S16 big_external_data_label-0x8000 +0+012c <[^>]*> stwio r4,0\(zero\) +[ ]*12c: R_NIOS2_S16 small_external_data_label-0x8000 +0+0130 <[^>]*> stwio r4,0\(zero\) +[ ]*130: R_NIOS2_S16 big_external_common-0x8000 +0+0134 <[^>]*> stwio r4,0\(zero\) +[ ]*134: R_NIOS2_S16 small_external_common-0x8000 +0+0138 <[^>]*> stwio r4,0\(zero\) +[ ]*138: R_NIOS2_S16 .bss-0x8000 +0+013c <[^>]*> stwio r4,0\(zero\) +[ ]*13c: R_NIOS2_S16 .bss-0x4000 +0+0140 <[^>]*> stwio r4,0\(zero\) +[ ]*140: R_NIOS2_S16 .data\+0x10000 +0+0144 <[^>]*> stwio r4,0\(r5\) +[ ]*144: R_NIOS2_S16 .data +0+0148 <[^>]*> stwio r4,0\(r5\) +[ ]*148: R_NIOS2_S16 big_external_data_label +0+014c <[^>]*> stwio r4,0\(r5\) +[ ]*14c: R_NIOS2_S16 small_external_data_label +0+0150 <[^>]*> stwio r4,0\(r5\) +[ ]*150: R_NIOS2_S16 big_external_common +0+0154 <[^>]*> stwio r4,0\(r5\) +[ ]*154: R_NIOS2_S16 small_external_common +0+0158 <[^>]*> stwio r4,0\(r5\) +[ ]*158: R_NIOS2_S16 .bss +0+015c <[^>]*> stwio r4,0\(r5\) +[ ]*15c: R_NIOS2_S16 .bss\+0x4000 +0+0160 <[^>]*> stwio r4,0\(r5\) +[ ]*160: R_NIOS2_S16 .data\+0x4 +0+0164 <[^>]*> stwio r4,0\(r5\) +[ ]*164: R_NIOS2_S16 big_external_data_label\+0x4 +0+0168 <[^>]*> stwio r4,0\(r5\) +[ ]*168: R_NIOS2_S16 small_external_data_label\+0x4 +0+016c <[^>]*> stwio r4,0\(r5\) +[ ]*16c: R_NIOS2_S16 big_external_common\+0x4 +0+0170 <[^>]*> stwio r4,0\(r5\) +[ ]*170: R_NIOS2_S16 small_external_common\+0x4 +0+0174 <[^>]*> stwio r4,0\(r5\) +[ ]*174: R_NIOS2_S16 .bss\+0x4 +0+0178 <[^>]*> stwio r4,0\(r5\) +[ ]*178: R_NIOS2_S16 .bss\+0x4004 +0+017c <[^>]*> stwio r4,0\(r5\) +[ ]*17c: R_NIOS2_S16 .data-0x8000 +0+0180 <[^>]*> stwio r4,0\(r5\) +[ ]*180: R_NIOS2_S16 big_external_data_label-0x8000 +0+0184 <[^>]*> stwio r4,0\(r5\) +[ ]*184: R_NIOS2_S16 small_external_data_label-0x8000 +0+0188 <[^>]*> stwio r4,0\(r5\) +[ ]*188: R_NIOS2_S16 big_external_common-0x8000 +0+018c <[^>]*> stwio r4,0\(r5\) +[ ]*18c: R_NIOS2_S16 small_external_common-0x8000 +0+0190 <[^>]*> stwio r4,0\(r5\) +[ ]*190: R_NIOS2_S16 .bss-0x8000 +0+0194 <[^>]*> stwio r4,0\(r5\) +[ ]*194: R_NIOS2_S16 .bss-0x4000 diff --git a/gas/testsuite/gas/nios2/stw.s b/gas/testsuite/gas/nios2/stw.s new file mode 100644 index 0000000..fa5c72f --- /dev/null +++ b/gas/testsuite/gas/nios2/stw.s @@ -0,0 +1,117 @@ + .data +data_label: + .extern big_external_data_label,0x4000 + .extern small_external_data_label,4 + .comm big_external_common,0x4000 + .comm small_external_common,4 + .lcomm big_local_common,0x4000 + .lcomm small_local_common,4 + +# the small symbols should have space allocated in the sbss section +# but this is not yet supported in the assembler, so space is allocated +# in the .bss section and the relocations are not gp-relative. this will +# be updated when gp-relative relocations are added + .text + stw r4,0(r0) + stw r4,4(r0) + stw r4,0x7ffc(r0) + stw r4,-0x8000(r0) + stw r4,0(r5) + stw r4,4(r5) + stw r4,0x7ffc(r5) + stw r4,-0x8000(r5) + stw r4,data_label(r0) + stw r4,big_external_data_label(r0) + stw r4,small_external_data_label(r0) + stw r4,big_external_common(r0) + stw r4,small_external_common(r0) + stw r4,big_local_common(r0) + stw r4,small_local_common(r0) + stw r4,data_label+4(r0) + stw r4,big_external_data_label+4(r0) + stw r4,small_external_data_label+4(r0) + stw r4,big_external_common+4(r0) + stw r4,small_external_common+4(r0) + stw r4,big_local_common+4(r0) + stw r4,small_local_common+4(r0) + stw r4,data_label-0x8000(r0) + stw r4,big_external_data_label-0x8000(r0) + stw r4,small_external_data_label-0x8000(r0) + stw r4,big_external_common-0x8000(r0) + stw r4,small_external_common-0x8000(r0) + stw r4,big_local_common-0x8000(r0) + stw r4,small_local_common-0x8000(r0) + stw r4,data_label+0x10000(r0) + stw r4,data_label(r5) + stw r4,big_external_data_label(r5) + stw r4,small_external_data_label(r5) + stw r4,big_external_common(r5) + stw r4,small_external_common(r5) + stw r4,big_local_common(r5) + stw r4,small_local_common(r5) + stw r4,data_label+4(r5) + stw r4,big_external_data_label+4(r5) + stw r4,small_external_data_label+4(r5) + stw r4,big_external_common+4(r5) + stw r4,small_external_common+4(r5) + stw r4,big_local_common+4(r5) + stw r4,small_local_common+4(r5) + stw r4,data_label-0x8000(r5) + stw r4,big_external_data_label-0x8000(r5) + stw r4,small_external_data_label-0x8000(r5) + stw r4,big_external_common-0x8000(r5) + stw r4,small_external_common-0x8000(r5) + stw r4,big_local_common-0x8000(r5) + stw r4,small_local_common-0x8000(r5) + + stwio r4,0(r0) + stwio r4,4(r0) + stwio r4,0x7ffc(r0) + stwio r4,-0x8000(r0) + stwio r4,0(r5) + stwio r4,4(r5) + stwio r4,0x7ffc(r5) + stwio r4,-0x8000(r5) + stwio r4,data_label(r0) + stwio r4,big_external_data_label(r0) + stwio r4,small_external_data_label(r0) + stwio r4,big_external_common(r0) + stwio r4,small_external_common(r0) + stwio r4,big_local_common(r0) + stwio r4,small_local_common(r0) + stwio r4,data_label+4(r0) + stwio r4,big_external_data_label+4(r0) + stwio r4,small_external_data_label+4(r0) + stwio r4,big_external_common+4(r0) + stwio r4,small_external_common+4(r0) + stwio r4,big_local_common+4(r0) + stwio r4,small_local_common+4(r0) + stwio r4,data_label-0x8000(r0) + stwio r4,big_external_data_label-0x8000(r0) + stwio r4,small_external_data_label-0x8000(r0) + stwio r4,big_external_common-0x8000(r0) + stwio r4,small_external_common-0x8000(r0) + stwio r4,big_local_common-0x8000(r0) + stwio r4,small_local_common-0x8000(r0) + stwio r4,data_label+0x10000(r0) + stwio r4,data_label(r5) + stwio r4,big_external_data_label(r5) + stwio r4,small_external_data_label(r5) + stwio r4,big_external_common(r5) + stwio r4,small_external_common(r5) + stwio r4,big_local_common(r5) + stwio r4,small_local_common(r5) + stwio r4,data_label+4(r5) + stwio r4,big_external_data_label+4(r5) + stwio r4,small_external_data_label+4(r5) + stwio r4,big_external_common+4(r5) + stwio r4,small_external_common+4(r5) + stwio r4,big_local_common+4(r5) + stwio r4,small_local_common+4(r5) + stwio r4,data_label-0x8000(r5) + stwio r4,big_external_data_label-0x8000(r5) + stwio r4,small_external_data_label-0x8000(r5) + stwio r4,big_external_common-0x8000(r5) + stwio r4,small_external_common-0x8000(r5) + stwio r4,big_local_common-0x8000(r5) + stwio r4,small_local_common-0x8000(r5) diff --git a/gas/testsuite/gas/nios2/sub.d b/gas/testsuite/gas/nios2/sub.d new file mode 100644 index 0000000..69b0285 --- /dev/null +++ b/gas/testsuite/gas/nios2/sub.d @@ -0,0 +1,10 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 sub + +# Test the add instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> sub r4,r4,r4 + diff --git a/gas/testsuite/gas/nios2/sub.s b/gas/testsuite/gas/nios2/sub.s new file mode 100644 index 0000000..34f00da --- /dev/null +++ b/gas/testsuite/gas/nios2/sub.s @@ -0,0 +1,4 @@ +# Source file used to test the add and addi instructions. + +foo: + sub r4,r4,r4 diff --git a/gas/testsuite/gas/nios2/sync.d b/gas/testsuite/gas/nios2/sync.d new file mode 100644 index 0000000..f0949e2 --- /dev/null +++ b/gas/testsuite/gas/nios2/sync.d @@ -0,0 +1,8 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 sync + +.*: +file format elf32-littlenios2 + +Disassembly of section \.text: +0+0000 <foo> sync + diff --git a/gas/testsuite/gas/nios2/sync.s b/gas/testsuite/gas/nios2/sync.s new file mode 100644 index 0000000..fe05d47 --- /dev/null +++ b/gas/testsuite/gas/nios2/sync.s @@ -0,0 +1,5 @@ +# Source file used to test the sync instructions +foo: + sync + + diff --git a/gas/testsuite/gas/nios2/trap.d b/gas/testsuite/gas/nios2/trap.d new file mode 100644 index 0000000..003ff69 --- /dev/null +++ b/gas/testsuite/gas/nios2/trap.d @@ -0,0 +1,7 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 trap + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> trap diff --git a/gas/testsuite/gas/nios2/trap.s b/gas/testsuite/gas/nios2/trap.s new file mode 100644 index 0000000..1eb3c7e --- /dev/null +++ b/gas/testsuite/gas/nios2/trap.s @@ -0,0 +1,3 @@ +# Source file used to test the ret instructions +foo: + trap diff --git a/gas/testsuite/gas/nios2/tret.d b/gas/testsuite/gas/nios2/tret.d new file mode 100644 index 0000000..48e2b51 --- /dev/null +++ b/gas/testsuite/gas/nios2/tret.d @@ -0,0 +1,8 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 tret + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> eret + diff --git a/gas/testsuite/gas/nios2/tret.s b/gas/testsuite/gas/nios2/tret.s new file mode 100644 index 0000000..42179f1 --- /dev/null +++ b/gas/testsuite/gas/nios2/tret.s @@ -0,0 +1,5 @@ +# Source file used to test the ret instructions +foo: + eret + + diff --git a/gas/testsuite/gas/nios2/warn_noat.l b/gas/testsuite/gas/nios2/warn_noat.l new file mode 100644 index 0000000..6bc5150 --- /dev/null +++ b/gas/testsuite/gas/nios2/warn_noat.l @@ -0,0 +1,5 @@ +.*warn_noat.s: Assembler messages: +.*warn_noat.s:2: Warning: Register at \(r1\) can sometimes be corrupted by assembler optimizations. +Use .set noat to turn off those optimizations \(and this warning\). +.*warn_noat.s:8: Warning: Register at \(r1\) can sometimes be corrupted by assembler optimizations. +Use .set noat to turn off those optimizations \(and this warning\). diff --git a/gas/testsuite/gas/nios2/warn_noat.s b/gas/testsuite/gas/nios2/warn_noat.s new file mode 100644 index 0000000..e99126e --- /dev/null +++ b/gas/testsuite/gas/nios2/warn_noat.s @@ -0,0 +1,8 @@ +.set noat, 2 # This should not cause warning for at to be turned off +add at, r2, r2 +.set noat # this should turn the warnings off +add at, r2, r2 +.set at, 3 # this should not turn the warnings on +add at, r2, r2 +.set at # this should turn the warnings on +add at, r2, r2 diff --git a/gas/testsuite/gas/nios2/warn_nobreak.l b/gas/testsuite/gas/nios2/warn_nobreak.l new file mode 100644 index 0000000..539813d --- /dev/null +++ b/gas/testsuite/gas/nios2/warn_nobreak.l @@ -0,0 +1,9 @@ +.*warn_nobreak.s: Assembler messages: +.*warn_nobreak.s:2: Warning: The debugger will corrupt ba \(r30\). If you don't need to debug this +code then use .set nobreak to turn off this warning. +.*warn_nobreak.s:3: Warning: The debugger will corrupt bt \(r25\). If you don't need to debug this +code then use .set nobreak to turn off this warning. +.*warn_nobreak.s:11: Warning: The debugger will corrupt ba \(r30\). If you don't need to debug this +code then use .set nobreak to turn off this warning. +.*warn_nobreak.s:12: Warning: The debugger will corrupt bt \(r25\). If you don't need to debug this +code then use .set nobreak to turn off this warning. diff --git a/gas/testsuite/gas/nios2/warn_nobreak.s b/gas/testsuite/gas/nios2/warn_nobreak.s new file mode 100644 index 0000000..8e495c0 --- /dev/null +++ b/gas/testsuite/gas/nios2/warn_nobreak.s @@ -0,0 +1,12 @@ +.set nobreak , 2 # This should not cause warning for ba, bt to be turned off +add ba, r2, r2 +add bt, r2, r2 +.set nobreak # this should turn the warnings off +add ba, r3, r4 +add bt, r3, r4 +.set break, 3 # this should not turn the warnings on +add ba, r3, r4 +add bt, r3, r4 +.set break # this should turn the warnings on +add ba, r3, r4 +add bt, r3, r4 diff --git a/gas/testsuite/gas/nios2/xor.d b/gas/testsuite/gas/nios2/xor.d new file mode 100644 index 0000000..de137dc --- /dev/null +++ b/gas/testsuite/gas/nios2/xor.d @@ -0,0 +1,11 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 xor + +# Test the nor instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> xor r6,r8,r10 +0+0004 <[^>]*> xorhi r6,r7,65535 +0+0008 <[^>]*> xori r6,r7,65535 diff --git a/gas/testsuite/gas/nios2/xor.s b/gas/testsuite/gas/nios2/xor.s new file mode 100644 index 0000000..2c558f7 --- /dev/null +++ b/gas/testsuite/gas/nios2/xor.s @@ -0,0 +1,7 @@ +# Source file used to test the nor instruction + +foo: + xor r6,r8,r10 + xorhi r6,r7,0xffff + xori r6,r7,0xffff + diff --git a/include/ChangeLog b/include/ChangeLog index 3d093d7..b34099b 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,11 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * dis-asm.h (print_insn_big_nios2): Declare. + (print_insn_little_nios2): Declare. + 2013-01-30 Kai Tietz <ktietz@redhat.com> PR other/54620 diff --git a/include/dis-asm.h b/include/dis-asm.h index 43c26b1..78e9fc0 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -226,6 +226,7 @@ extern int print_insn_avr (bfd_vma, disassemble_info *); extern int print_insn_bfin (bfd_vma, disassemble_info *); extern int print_insn_big_arm (bfd_vma, disassemble_info *); extern int print_insn_big_mips (bfd_vma, disassemble_info *); +extern int print_insn_big_nios2 (bfd_vma, disassemble_info *); extern int print_insn_big_or32 (bfd_vma, disassemble_info *); extern int print_insn_big_powerpc (bfd_vma, disassemble_info *); extern int print_insn_big_score (bfd_vma, disassemble_info *); @@ -253,6 +254,7 @@ extern int print_insn_ip2k (bfd_vma, disassemble_info *); extern int print_insn_iq2000 (bfd_vma, disassemble_info *); extern int print_insn_little_arm (bfd_vma, disassemble_info *); extern int print_insn_little_mips (bfd_vma, disassemble_info *); +extern int print_insn_little_nios2 (bfd_vma, disassemble_info *); extern int print_insn_little_or32 (bfd_vma, disassemble_info *); extern int print_insn_little_powerpc (bfd_vma, disassemble_info *); extern int print_insn_little_score (bfd_vma, disassemble_info *); diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index 82e884e..7807767 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,10 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * nios2.h: New file. + 2013-01-24 Nick Clifton <nickc@redhat.com> * v850.h: Add support for e3v5 architecture. diff --git a/include/elf/nios2.h b/include/elf/nios2.h new file mode 100644 index 0000000..ff5947b --- /dev/null +++ b/include/elf/nios2.h @@ -0,0 +1,91 @@ +/* Altera Nios II ELF support for BFD. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. */ + + +/* This file holds definitions specific to the Altera Nios II ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_NIOS2_H +#define _ELF_NIOS2_H + +#include "elf/reloc-macros.h" + +/* The order of these numbers must match the order in + the elf_nios2_howto_table_rel table for the lookup + function to work properly. */ + +START_RELOC_NUMBERS (elf_nios2_reloc_type) + RELOC_NUMBER (R_NIOS2_NONE, 0) + RELOC_NUMBER (R_NIOS2_S16, 1) + RELOC_NUMBER (R_NIOS2_U16, 2) + RELOC_NUMBER (R_NIOS2_PCREL16, 3) + RELOC_NUMBER (R_NIOS2_CALL26, 4) + RELOC_NUMBER (R_NIOS2_IMM5, 5) + RELOC_NUMBER (R_NIOS2_CACHE_OPX, 6) + RELOC_NUMBER (R_NIOS2_IMM6, 7) + RELOC_NUMBER (R_NIOS2_IMM8, 8) + RELOC_NUMBER (R_NIOS2_HI16, 9) + RELOC_NUMBER (R_NIOS2_LO16, 10) + RELOC_NUMBER (R_NIOS2_HIADJ16, 11) + RELOC_NUMBER (R_NIOS2_BFD_RELOC_32, 12) + RELOC_NUMBER (R_NIOS2_BFD_RELOC_16, 13) + RELOC_NUMBER (R_NIOS2_BFD_RELOC_8, 14) + RELOC_NUMBER (R_NIOS2_GPREL, 15) + RELOC_NUMBER (R_NIOS2_GNU_VTINHERIT, 16) + RELOC_NUMBER (R_NIOS2_GNU_VTENTRY, 17) + RELOC_NUMBER (R_NIOS2_UJMP, 18) + RELOC_NUMBER (R_NIOS2_CJMP, 19) + RELOC_NUMBER (R_NIOS2_CALLR, 20) + RELOC_NUMBER (R_NIOS2_ALIGN, 21) + RELOC_NUMBER (R_NIOS2_GOT16, 22) + RELOC_NUMBER (R_NIOS2_CALL16, 23) + RELOC_NUMBER (R_NIOS2_GOTOFF_LO, 24) + RELOC_NUMBER (R_NIOS2_GOTOFF_HA, 25) + RELOC_NUMBER (R_NIOS2_PCREL_LO, 26) + RELOC_NUMBER (R_NIOS2_PCREL_HA, 27) + RELOC_NUMBER (R_NIOS2_TLS_GD16, 28) + RELOC_NUMBER (R_NIOS2_TLS_LDM16, 29) + RELOC_NUMBER (R_NIOS2_TLS_LDO16, 30) + RELOC_NUMBER (R_NIOS2_TLS_IE16, 31) + RELOC_NUMBER (R_NIOS2_TLS_LE16, 32) + RELOC_NUMBER (R_NIOS2_TLS_DTPMOD, 33) + RELOC_NUMBER (R_NIOS2_TLS_DTPREL, 34) + RELOC_NUMBER (R_NIOS2_TLS_TPREL, 35) + RELOC_NUMBER (R_NIOS2_COPY, 36) + RELOC_NUMBER (R_NIOS2_GLOB_DAT, 37) + RELOC_NUMBER (R_NIOS2_JUMP_SLOT, 38) + RELOC_NUMBER (R_NIOS2_RELATIVE, 39) + RELOC_NUMBER (R_NIOS2_GOTOFF, 40) + RELOC_NUMBER (R_NIOS2_ILLEGAL, 41) +END_RELOC_NUMBERS (R_NIOS2_maxext) + +/* Processor-specific section flags. */ + +/* This is used to mark gp-relative sections. */ +#define SHF_NIOS2_GPREL 0x10000000 + +/* Processor-specific dynamic array tags. */ + +/* Address of _gp. */ +#define DT_NIOS2_GP 0x70000002 + +#endif /* _ELF_NIOS2_H */ diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index ebe33dc..cef6986 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,10 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * nios2.h: New file. + 2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com> * aarch64.h (aarch64_op): Add OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2. diff --git a/include/opcode/nios2.h b/include/opcode/nios2.h new file mode 100644 index 0000000..85e7023 --- /dev/null +++ b/include/opcode/nios2.h @@ -0,0 +1,517 @@ +/* Nios II opcode list for GAS, the GNU assembler. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + + 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. */ + +#ifndef _NIOS2_H_ +#define _NIOS2_H_ + +#include "bfd.h" + +/**************************************************************************** + * This file contains structures, bit masks and shift counts used + * by the GNU toolchain to define the Nios II instruction set and + * access various opcode fields. + ****************************************************************************/ + +/* Identify different overflow situations for error messages. */ +enum overflow_type +{ + call_target_overflow = 0, + branch_target_overflow, + address_offset_overflow, + signed_immed16_overflow, + unsigned_immed16_overflow, + unsigned_immed5_overflow, + custom_opcode_overflow, + no_overflow +}; + +/* This structure holds information for a particular instruction. + + The args field is a string describing the operands. The following + letters can appear in the args: + c - a 5-bit control register index or break opcode + d - a 5-bit destination register index + s - a 5-bit left source register index + t - a 5-bit right source register index + i - a 16-bit signed immediate + u - a 16-bit unsigned immediate + j - a 5-bit unsigned immediate + k - a 6-bit unsigned immediate + l - an 8-bit unsigned immediate + m - a 26-bit unsigned immediate + Literal ',', '(', and ')' characters may also appear in the args as + delimiters. + + The pinfo field is INSN_MACRO for a macro. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. + + When assembling, the match field contains the opcode template, which + is modified by the arguments to produce the actual opcode + that is emitted. If pinfo is INSN_MACRO, then this is 0. + + If pinfo is INSN_MACRO, the mask field stores the macro identifier. + Otherwise this is a bit mask for the relevant portions of the opcode + when disassembling. If the actual opcode anded with the match field + equals the opcode field, then we have found the correct instruction. */ + +struct nios2_opcode +{ + const char *name; /* The name of the instruction. */ + const char *args; /* A string describing the arguments for this + instruction. */ + const char *args_test; /* Like args, but with an extra argument for + the expected opcode. */ + unsigned long num_args; /* The number of arguments the instruction + takes. */ + unsigned long match; /* The basic opcode for the instruction. */ + unsigned long mask; /* Mask for the opcode field of the + instruction. */ + unsigned long pinfo; /* Is this a real instruction or instruction + macro? */ + enum overflow_type overflow_msg; /* Used to generate informative + message when fixup overflows. */ +}; + +/* This value is used in the nios2_opcode.pinfo field to indicate that the + instruction is a macro or pseudo-op. This requires special treatment by + the assembler, and is used by the disassembler to determine whether to + check for a nop. */ +#define NIOS2_INSN_MACRO 0x80000000 +#define NIOS2_INSN_MACRO_MOV 0x80000001 +#define NIOS2_INSN_MACRO_MOVI 0x80000002 +#define NIOS2_INSN_MACRO_MOVIA 0x80000004 + +#define NIOS2_INSN_RELAXABLE 0x40000000 +#define NIOS2_INSN_UBRANCH 0x00000010 +#define NIOS2_INSN_CBRANCH 0x00000020 +#define NIOS2_INSN_CALL 0x00000040 + +#define NIOS2_INSN_ADDI 0x00000080 +#define NIOS2_INSN_ANDI 0x00000100 +#define NIOS2_INSN_ORI 0x00000200 +#define NIOS2_INSN_XORI 0x00000400 + + +/* Associates a register name ($6) with a 5-bit index (eg 6). */ +struct nios2_reg +{ + const char *name; + const int index; +}; + + +/* These are bit masks and shift counts for accessing the various + fields of a Nios II instruction. */ + +/* Macros for getting and setting an instruction field. */ +#define GET_INSN_FIELD(X, i) \ + (((i) & OP_MASK_##X) >> OP_SH_##X) +#define SET_INSN_FIELD(X, i, j) \ + ((i) = (((i) & ~OP_MASK_##X) | (((j) << OP_SH_##X) & OP_MASK_##X))) + +/* Instruction field definitions. */ +#define IW_A_LSB 27 +#define IW_A_MSB 31 +#define IW_A_SZ 5 +#define IW_A_MASK 0x1f + +#define IW_B_LSB 22 +#define IW_B_MSB 26 +#define IW_B_SZ 5 +#define IW_B_MASK 0x1f + +#define IW_C_LSB 17 +#define IW_C_MSB 21 +#define IW_C_SZ 5 +#define IW_C_MASK 0x1f + +#define IW_IMM16_LSB 6 +#define IW_IMM16_MSB 21 +#define IW_IMM16_SZ 16 +#define IW_IMM16_MASK 0xffff + +#define IW_IMM26_LSB 6 +#define IW_IMM26_MSB 31 +#define IW_IMM26_SZ 26 +#define IW_IMM26_MASK 0x3ffffff + +#define IW_OP_LSB 0 +#define IW_OP_MSB 5 +#define IW_OP_SZ 6 +#define IW_OP_MASK 0x3f + +#define IW_OPX_LSB 11 +#define IW_OPX_MSB 16 +#define IW_OPX_SZ 6 +#define IW_OPX_MASK 0x3f + +#define IW_SHIFT_IMM5_LSB 6 +#define IW_SHIFT_IMM5_MSB 10 +#define IW_SHIFT_IMM5_SZ 5 +#define IW_SHIFT_IMM5_MASK 0x1f + +#define IW_CONTROL_REGNUM_LSB 6 +#define IW_CONTROL_REGNUM_MSB 9 +#define IW_CONTROL_REGNUM_SZ 4 +#define IW_CONTROL_REGNUM_MASK 0xf + +/* Operator mask and shift. */ +#define OP_MASK_OP (IW_OP_MASK << IW_OP_LSB) +#define OP_SH_OP IW_OP_LSB + +/* Masks and shifts for I-type instructions. */ +#define OP_MASK_IOP (IW_OP_MASK << IW_OP_LSB) +#define OP_SH_IOP IW_OP_LSB + +#define OP_MASK_IMM16 (IW_IMM16_MASK << IW_IMM16_LSB) +#define OP_SH_IMM16 IW_IMM16_LSB + +#define OP_MASK_IRD (IW_B_MASK << IW_B_LSB) +#define OP_SH_IRD IW_B_LSB /* The same as T for I-type. */ + +#define OP_MASK_IRT (IW_B_MASK << IW_B_LSB) +#define OP_SH_IRT IW_B_LSB + +#define OP_MASK_IRS (IW_A_MASK << IW_A_LSB) +#define OP_SH_IRS IW_A_LSB + +/* Masks and shifts for R-type instructions. */ +#define OP_MASK_ROP (IW_OP_MASK << IW_OP_LSB) +#define OP_SH_ROP IW_OP_LSB + +#define OP_MASK_ROPX (IW_OPX_MASK << IW_OPX_LSB) +#define OP_SH_ROPX IW_OPX_LSB + +#define OP_MASK_RRD (IW_C_MASK << IW_C_LSB) +#define OP_SH_RRD IW_C_LSB + +#define OP_MASK_RRT (IW_B_MASK << IW_B_LSB) +#define OP_SH_RRT IW_B_LSB + +#define OP_MASK_RRS (IW_A_MASK << IW_A_LSB) +#define OP_SH_RRS IW_A_LSB + +/* Masks and shifts for J-type instructions. */ +#define OP_MASK_JOP (IW_OP_MASK << IW_OP_LSB) +#define OP_SH_JOP IW_OP_LSB + +#define OP_MASK_IMM26 (IW_IMM26_MASK << IW_IMM26_LSB) +#define OP_SH_IMM26 IW_IMM26_LSB + +/* Masks and shifts for CTL instructions. */ +#define OP_MASK_RCTL 0x000007c0 +#define OP_SH_RCTL 6 + +/* Break instruction imm5 field. */ +#define OP_MASK_TRAP_IMM5 0x000007c0 +#define OP_SH_TRAP_IMM5 6 + +/* Instruction imm5 field. */ +#define OP_MASK_IMM5 (IW_SHIFT_IMM5_MASK << IW_SHIFT_IMM5_LSB) +#define OP_SH_IMM5 IW_SHIFT_IMM5_LSB + +/* Cache operation fields (type j,i(s)). */ +#define OP_MASK_CACHE_OPX (IW_B_MASK << IW_B_LSB) +#define OP_SH_CACHE_OPX IW_B_LSB +#define OP_MASK_CACHE_RRS (IW_A_MASK << IW_A_LSB) +#define OP_SH_CACHE_RRS IW_A_LSB + +/* Custom instruction masks. */ +#define OP_MASK_CUSTOM_A 0x00010000 +#define OP_SH_CUSTOM_A 16 + +#define OP_MASK_CUSTOM_B 0x00008000 +#define OP_SH_CUSTOM_B 15 + +#define OP_MASK_CUSTOM_C 0x00004000 +#define OP_SH_CUSTOM_C 14 + +#define OP_MASK_CUSTOM_N 0x00003fc0 +#define OP_SH_CUSTOM_N 6 +#define OP_MAX_CUSTOM_N 255 + +/* OP instruction values. */ +#define OP_ADDI 4 +#define OP_ANDHI 44 +#define OP_ANDI 12 +#define OP_BEQ 38 +#define OP_BGE 14 +#define OP_BGEU 46 +#define OP_BLT 22 +#define OP_BLTU 54 +#define OP_BNE 30 +#define OP_BR 6 +#define OP_CALL 0 +#define OP_CMPEQI 32 +#define OP_CMPGEI 8 +#define OP_CMPGEUI 40 +#define OP_CMPLTI 16 +#define OP_CMPLTUI 48 +#define OP_CMPNEI 24 +#define OP_CUSTOM 50 +#define OP_FLUSHD 59 +#define OP_FLUSHDA 27 +#define OP_INITD 51 +#define OP_INITDA 19 +#define OP_JMPI 1 +#define OP_LDB 7 +#define OP_LDBIO 39 +#define OP_LDBU 3 +#define OP_LDBUIO 35 +#define OP_LDH 15 +#define OP_LDHIO 47 +#define OP_LDHU 11 +#define OP_LDHUIO 43 +#define OP_LDL 31 +#define OP_LDW 23 +#define OP_LDWIO 55 +#define OP_MULI 36 +#define OP_OPX 58 +#define OP_ORHI 52 +#define OP_ORI 20 +#define OP_STB 5 +#define OP_STBIO 37 +#define OP_STC 29 +#define OP_STH 13 +#define OP_STHIO 45 +#define OP_STW 21 +#define OP_STWIO 53 +#define OP_XORHI 60 +#define OP_XORI 28 + +/* OPX instruction values. */ +#define OPX_ADD 49 +#define OPX_AND 14 +#define OPX_BREAK 52 +#define OPX_BRET 9 +#define OPX_CALLR 29 +#define OPX_CMPEQ 32 +#define OPX_CMPGE 8 +#define OPX_CMPGEU 40 +#define OPX_CMPLT 16 +#define OPX_CMPLTU 48 +#define OPX_CMPNE 24 +#define OPX_CRST 62 +#define OPX_DIV 37 +#define OPX_DIVU 36 +#define OPX_ERET 1 +#define OPX_FLUSHI 12 +#define OPX_FLUSHP 4 +#define OPX_HBREAK 53 +#define OPX_INITI 41 +#define OPX_INTR 61 +#define OPX_JMP 13 +#define OPX_MUL 39 +#define OPX_MULXSS 31 +#define OPX_MULXSU 23 +#define OPX_MULXUU 7 +#define OPX_NEXTPC 28 +#define OPX_NOR 6 +#define OPX_OR 22 +#define OPX_RDCTL 38 +#define OPX_RET 5 +#define OPX_ROL 3 +#define OPX_ROLI 2 +#define OPX_ROR 11 +#define OPX_SLL 19 +#define OPX_SLLI 18 +#define OPX_SRA 59 +#define OPX_SRAI 58 +#define OPX_SRL 27 +#define OPX_SRLI 26 +#define OPX_SUB 57 +#define OPX_SYNC 54 +#define OPX_TRAP 45 +#define OPX_WRCTL 46 +#define OPX_XOR 30 + +/* The following macros define the opcode matches for each + instruction code & OP_MASK_INST == OP_MATCH_INST. */ + +/* OP instruction matches. */ +#define OP_MATCH_ADDI OP_ADDI +#define OP_MATCH_ANDHI OP_ANDHI +#define OP_MATCH_ANDI OP_ANDI +#define OP_MATCH_BEQ OP_BEQ +#define OP_MATCH_BGE OP_BGE +#define OP_MATCH_BGEU OP_BGEU +#define OP_MATCH_BLT OP_BLT +#define OP_MATCH_BLTU OP_BLTU +#define OP_MATCH_BNE OP_BNE +#define OP_MATCH_BR OP_BR +#define OP_MATCH_FLUSHD OP_FLUSHD +#define OP_MATCH_FLUSHDA OP_FLUSHDA +#define OP_MATCH_INITD OP_INITD +#define OP_MATCH_INITDA OP_INITDA +#define OP_MATCH_CALL OP_CALL +#define OP_MATCH_CMPEQI OP_CMPEQI +#define OP_MATCH_CMPGEI OP_CMPGEI +#define OP_MATCH_CMPGEUI OP_CMPGEUI +#define OP_MATCH_CMPLTI OP_CMPLTI +#define OP_MATCH_CMPLTUI OP_CMPLTUI +#define OP_MATCH_CMPNEI OP_CMPNEI +#define OP_MATCH_JMPI OP_JMPI +#define OP_MATCH_LDB OP_LDB +#define OP_MATCH_LDBIO OP_LDBIO +#define OP_MATCH_LDBU OP_LDBU +#define OP_MATCH_LDBUIO OP_LDBUIO +#define OP_MATCH_LDH OP_LDH +#define OP_MATCH_LDHIO OP_LDHIO +#define OP_MATCH_LDHU OP_LDHU +#define OP_MATCH_LDHUIO OP_LDHUIO +#define OP_MATCH_LDL OP_LDL +#define OP_MATCH_LDW OP_LDW +#define OP_MATCH_LDWIO OP_LDWIO +#define OP_MATCH_MULI OP_MULI +#define OP_MATCH_OPX OP_OPX +#define OP_MATCH_ORHI OP_ORHI +#define OP_MATCH_ORI OP_ORI +#define OP_MATCH_STB OP_STB +#define OP_MATCH_STBIO OP_STBIO +#define OP_MATCH_STC OP_STC +#define OP_MATCH_STH OP_STH +#define OP_MATCH_STHIO OP_STHIO +#define OP_MATCH_STW OP_STW +#define OP_MATCH_STWIO OP_STWIO +#define OP_MATCH_CUSTOM OP_CUSTOM +#define OP_MATCH_XORHI OP_XORHI +#define OP_MATCH_XORI OP_XORI +#define OP_MATCH_OPX OP_OPX + +/* OPX instruction values. */ +#define OPX_MATCH(code) ((code << IW_OPX_LSB) | OP_OPX) + +#define OP_MATCH_ADD OPX_MATCH (OPX_ADD) +#define OP_MATCH_AND OPX_MATCH (OPX_AND) +#define OP_MATCH_BREAK ((0x1e << 17) | OPX_MATCH (OPX_BREAK)) +#define OP_MATCH_BRET (0xf0000000 | OPX_MATCH (OPX_BRET)) +#define OP_MATCH_CALLR ((0x1f << 17) | OPX_MATCH (OPX_CALLR)) +#define OP_MATCH_CMPEQ OPX_MATCH (OPX_CMPEQ) +#define OP_MATCH_CMPGE OPX_MATCH (OPX_CMPGE) +#define OP_MATCH_CMPGEU OPX_MATCH (OPX_CMPGEU) +#define OP_MATCH_CMPLT OPX_MATCH (OPX_CMPLT) +#define OP_MATCH_CMPLTU OPX_MATCH (OPX_CMPLTU) +#define OP_MATCH_CMPNE OPX_MATCH (OPX_CMPNE) +#define OP_MATCH_DIV OPX_MATCH (OPX_DIV) +#define OP_MATCH_DIVU OPX_MATCH (OPX_DIVU) +#define OP_MATCH_JMP OPX_MATCH (OPX_JMP) +#define OP_MATCH_MUL OPX_MATCH (OPX_MUL) +#define OP_MATCH_MULXSS OPX_MATCH (OPX_MULXSS) +#define OP_MATCH_MULXSU OPX_MATCH (OPX_MULXSU) +#define OP_MATCH_MULXUU OPX_MATCH (OPX_MULXUU) +#define OP_MATCH_NEXTPC OPX_MATCH (OPX_NEXTPC) +#define OP_MATCH_NOR OPX_MATCH (OPX_NOR) +#define OP_MATCH_OR OPX_MATCH (OPX_OR) +#define OP_MATCH_RDCTL OPX_MATCH (OPX_RDCTL) +#define OP_MATCH_RET (0xf8000000 | OPX_MATCH (OPX_RET)) +#define OP_MATCH_ROL OPX_MATCH (OPX_ROL) +#define OP_MATCH_ROLI OPX_MATCH (OPX_ROLI) +#define OP_MATCH_ROR OPX_MATCH (OPX_ROR) +#define OP_MATCH_SLL OPX_MATCH (OPX_SLL) +#define OP_MATCH_SLLI OPX_MATCH (OPX_SLLI) +#define OP_MATCH_SRA OPX_MATCH (OPX_SRA) +#define OP_MATCH_SRAI OPX_MATCH (OPX_SRAI) +#define OP_MATCH_SRL OPX_MATCH (OPX_SRL) +#define OP_MATCH_SRLI OPX_MATCH (OPX_SRLI) +#define OP_MATCH_SUB OPX_MATCH (OPX_SUB) +#define OP_MATCH_SYNC OPX_MATCH (OPX_SYNC) +#define OP_MATCH_TRAP ((0x1d << 17) | OPX_MATCH (OPX_TRAP)) +#define OP_MATCH_ERET (0xe8000000 | OPX_MATCH (OPX_ERET)) +#define OP_MATCH_WRCTL OPX_MATCH (OPX_WRCTL) +#define OP_MATCH_XOR OPX_MATCH (OPX_XOR) +#define OP_MATCH_FLUSHI OPX_MATCH (OPX_FLUSHI) +#define OP_MATCH_FLUSHP OPX_MATCH (OPX_FLUSHP) +#define OP_MATCH_INITI OPX_MATCH (OPX_INITI) + +/* Some unusual op masks. */ +#define OP_MASK_BREAK ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_RRD \ + | OP_MASK_ROPX | OP_MASK_OP) \ + & 0xfffff03f) +#define OP_MASK_CALLR ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) +#define OP_MASK_JMP ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) +#define OP_MASK_SYNC ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) +#define OP_MASK_TRAP ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_RRD \ + | OP_MASK_ROPX | OP_MASK_OP) \ + & 0xfffff83f) +#define OP_MASK_WRCTL ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) /*& 0xfffff83f */ +#define OP_MASK_NEXTPC ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_ROPX \ + | OP_MASK_OP)) +#define OP_MASK_FLUSHI ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) +#define OP_MASK_INITI ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX \ + | OP_MASK_OP)) + +#define OP_MASK_ROLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) +#define OP_MASK_SLLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) +#define OP_MASK_SRAI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) +#define OP_MASK_SRLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) +#define OP_MASK_RDCTL ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_ROPX \ + | OP_MASK_OP)) /*& 0xfffff83f */ + +#ifndef OP_MASK +#define OP_MASK 0xffffffff +#endif + +/* These convenience macros to extract instruction fields are used by GDB. */ +#define GET_IW_A(Iw) \ + (((Iw) >> IW_A_LSB) & IW_A_MASK) +#define GET_IW_B(Iw) \ + (((Iw) >> IW_B_LSB) & IW_B_MASK) +#define GET_IW_C(Iw) \ + (((Iw) >> IW_C_LSB) & IW_C_MASK) +#define GET_IW_CONTROL_REGNUM(Iw) \ + (((Iw) >> IW_CONTROL_REGNUM_LSB) & IW_CONTROL_REGNUM_MASK) +#define GET_IW_IMM16(Iw) \ + (((Iw) >> IW_IMM16_LSB) & IW_IMM16_MASK) +#define GET_IW_IMM26(Iw) \ + (((Iw) >> IW_IMM26_LSB) & IW_IMM26_MASK) +#define GET_IW_OP(Iw) \ + (((Iw) >> IW_OP_LSB) & IW_OP_MASK) +#define GET_IW_OPX(Iw) \ + (((Iw) >> IW_OPX_LSB) & IW_OPX_MASK) + +/* These are the data structures we use to hold the instruction information. */ +extern const struct nios2_opcode nios2_builtin_opcodes[]; +extern const int bfd_nios2_num_builtin_opcodes; +extern struct nios2_opcode *nios2_opcodes; +extern int bfd_nios2_num_opcodes; + +/* These are the data structures used to hold the register information. */ +extern const struct nios2_reg nios2_builtin_regs[]; +extern struct nios2_reg *nios2_regs; +extern const int nios2_num_builtin_regs; +extern int nios2_num_regs; + +/* Machine-independent macro for number of opcodes. */ +#define NUMOPCODES bfd_nios2_num_opcodes +#define NUMREGISTERS nios2_num_regs; + +/* This is made extern so that the assembler can use it to find out + what instruction caused an error. */ +extern const struct nios2_opcode *nios2_find_opcode_hash (unsigned long); + +#endif /* _NIOS2_H */ diff --git a/ld/ChangeLog b/ld/ChangeLog index ec0c220..cf809f1 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,14 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * Makefile.am (enios2elf.c): New rule. + * Makefile.in: Regenerated. + * configure.tgt: Add case for nios2*-*-*. + * emulparams/nios2elf.sh: New file. + * NEWS: Note Altera Nios II support. + 2013-02-06 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com> * emultempl/avrelf.em (avr_elf_before_parse): New function. diff --git a/ld/Makefile.am b/ld/Makefile.am index 837a878..20b15b4 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -1770,6 +1770,9 @@ emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \ enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" +enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} nios2elf "$(tdir_nios2)" ens32knbsd.c: $(srcdir)/emulparams/ns32knbsd.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \ $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} diff --git a/ld/Makefile.in b/ld/Makefile.in index 3fd08fc..c09399a 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -3255,6 +3255,9 @@ emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \ enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" +enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} nios2elf "$(tdir_nios2)" ens32knbsd.c: $(srcdir)/emulparams/ns32knbsd.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \ $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} @@ -1,5 +1,7 @@ -*- text -*- +* Add support for Altera Nios II. + * Add support for the V850E3V5 architecture. * Add support for the Imagination Technologies Meta processor. diff --git a/ld/configure.tgt b/ld/configure.tgt index f4d1c31..b015dde 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -515,6 +515,7 @@ mt-*elf) targ_emul=elf32mt msp430-*-*) targ_emul=msp430x110 targ_extra_emuls="msp430x112 msp430x1101 msp430x1111 msp430x1121 msp430x1122 msp430x1132 msp430x122 msp430x123 msp430x1222 msp430x1232 msp430x133 msp430x135 msp430x1331 msp430x1351 msp430x147 msp430x148 msp430x149 msp430x155 msp430x156 msp430x157 msp430x167 msp430x168 msp430x169 msp430x1610 msp430x1611 msp430x1612 msp430x2101 msp430x2111 msp430x2121 msp430x2131 msp430x311 msp430x312 msp430x313 msp430x314 msp430x315 msp430x323 msp430x325 msp430x336 msp430x337 msp430x412 msp430x413 msp430x415 msp430x417 msp430xE423 msp430xE425 msp430xE427 msp430xW423 msp430xW425 msp430xW427 msp430xG437 msp430xG438 msp430xG439 msp430x435 msp430x436 msp430x437 msp430x447 msp430x448 msp430x449" ;; +nios2*-*-*) targ_emul=nios2elf ;; ns32k-pc532-mach* | ns32k-pc532-ux*) targ_emul=pc532macha ;; ns32k-*-netbsd* | ns32k-pc532-lites*) targ_emul=ns32knbsd ;; diff --git a/ld/emulparams/nios2elf.sh b/ld/emulparams/nios2elf.sh new file mode 100644 index 0000000..767f3de --- /dev/null +++ b/ld/emulparams/nios2elf.sh @@ -0,0 +1,20 @@ +SCRIPT_NAME=elf +TEMPLATE_NAME=elf32 +EXTRA_EM_FILE= +OUTPUT_FORMAT="elf32-littlenios2" +LITTLE_OUTPUT_FORMAT="elf32-littlenios2" +BIG_OUTPUT_FORMAT="elf32-bignios2" +TEXT_START_ADDR=0x1000 +OTHER_GOT_SYMBOLS=' + _gp = ALIGN(16) + 0x7ff0; + PROVIDE(gp = _gp); +' +ARCH=nios2 +MACHINE= +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" +ENTRY=_start +NOP=0x0001883a + +GENERATE_SHLIB_SCRIPT=yes +GENERATE_PIE_SCRIPT=yes diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index e172a1b..11535a6 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,49 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * ld-nios2/emit-relocs-1a.s: New. + * ld-nios2/emit-relocs-1b.s: New. + * ld-nios2/emit-relocs-1.d: New. + * ld-nios2/emit-relocs-1.ld: New. + * ld-nios2/gprel.d: New. + * ld-nios2/gprel.s: New. + * ld-nios2/hilo16.d: New. + * ld-nios2/hilo16.s: New. + * ld-nios2/hilo16_symbol.s: New. + * ld-nios2/imm5.d: New. + * ld-nios2/imm5.s: New. + * ld-nios2/imm5_symbol.s: New. + * ld-nios2/nios2.exp: New. + * ld-nios2/pcrel16.d: New. + * ld-nios2/pcrel16_label.s: New. + * ld-nios2/pcrel16.s: New. + * ld-nios2/relax_callr.d: New. + * ld-nios2/relax_callr.ld: New. + * ld-nios2/relax_callr.s: New. + * ld-nios2/relax_cjmp.d: New. + * ld-nios2/relax_cjmp.s: New. + * ld-nios2/relax_jmp.ld: New. + * ld-nios2/relax_section.d: New. + * ld-nios2/relax_section.s: New. + * ld-nios2/relax_ujmp.d: New. + * ld-nios2/relax_ujmp.s: New. + * ld-nios2/reloc.d: New. + * ld-nios2/reloc.s: New. + * ld-nios2/reloc_symbol.s: New. + * ld-nios2/s16.d: New. + * ld-nios2/s16.s: New. + * ld-nios2/s16_symbol.s: New. + * ld-nios2/u16.d: New. + * ld-nios2/u16.s: New. + * ld-nios2/u16_symbol.s: New. + * ld-elf/indirect.exp: Skip on targets that don't support + -shared -fPIC. + * ld-elfcomm/elfcomm.exp: Build with -G0 for nios2. + * ld-plugin/lto.exp: Skip shared library tests on targets that + don't support them. Skip execution tests on non-native targets. + 2013-02-06 H.J. Lu <hongjiu.lu@intel.com> * ld-elf/now-1.d: New file. diff --git a/ld/testsuite/ld-elf/indirect.exp b/ld/testsuite/ld-elf/indirect.exp index 07df2cc..d5d3abc 100644 --- a/ld/testsuite/ld-elf/indirect.exp +++ b/ld/testsuite/ld-elf/indirect.exp @@ -37,6 +37,11 @@ if { [which $CC] == 0 } { return } +# Some bare-metal targets don't support shared libs or PIC. +if { ![run_host_cmd_yesno $CC "-shared -fPIC $srcdir/$subdir/dummy.c -o tmpdir/t.so"] } { + return +} + proc check_link_message { cmd string testname } { send_log "$cmd\n" verbose "$cmd" diff --git a/ld/testsuite/ld-elfcomm/elfcomm.exp b/ld/testsuite/ld-elfcomm/elfcomm.exp index 572931b..c5c7539 100644 --- a/ld/testsuite/ld-elfcomm/elfcomm.exp +++ b/ld/testsuite/ld-elfcomm/elfcomm.exp @@ -181,6 +181,10 @@ proc assembler_generates_commons {} { return 1 } +if [istarget nios2*-*-*] { + set CFLAGS "$CFLAGS -G0" +} + # Explicitly use "-fcommon" so that even if $CFLAGS includes # "-fno-common", these tests are compiled as expected. if { ![ld_compile "$CC $CFLAGS -fcommon" $srcdir/$subdir/common1a.c tmpdir/common1a.o] diff --git a/ld/testsuite/ld-nios2/emit-relocs-1.d b/ld/testsuite/ld-nios2/emit-relocs-1.d new file mode 100644 index 0000000..aba0a53 --- /dev/null +++ b/ld/testsuite/ld-nios2/emit-relocs-1.d @@ -0,0 +1,37 @@ +#name: Emit relocs 1 +#source: emit-relocs-1a.s +#source: emit-relocs-1b.s +#ld: -q -T emit-relocs-1.ld +#objdump: -sr + +.*: file format .* + +RELOCATION RECORDS FOR \[\.data\]: +OFFSET TYPE VALUE * +00000000 R_NIOS2_BFD_RELOC32 \.data +00000004 R_NIOS2_BFD_RELOC32 \.data\+0x00001000 +00000008 R_NIOS2_BFD_RELOC32 \.merge1\+0x00000002 +0000000c R_NIOS2_BFD_RELOC32 \.merge2 +00000010 R_NIOS2_BFD_RELOC32 \.merge3 +00000014 R_NIOS2_BFD_RELOC32 \.merge3\+0x00000004 +00000020 R_NIOS2_BFD_RELOC32 \.data\+0x00000020 +00000024 R_NIOS2_BFD_RELOC32 \.data\+0x00001020 +00000028 R_NIOS2_BFD_RELOC32 \.merge1 +0000002c R_NIOS2_BFD_RELOC32 \.merge2\+0x00000002 +00000030 R_NIOS2_BFD_RELOC32 \.merge3\+0x00000008 +00000034 R_NIOS2_BFD_RELOC32 \.merge3\+0x00000004 + + +Contents of section \.text: + 80000 3a880100 00000000 00000000 00000000 .* +Contents of section \.merge1: + 80400 666c7574 74657200 flutter.* +Contents of section \.merge2: + 80800 74617374 696e6700 tasting.* +Contents of section \.merge3: + 80c00 00010000 00020000 00030000 .* +Contents of section \.data: + 81000 00100800 00200800 02040800 00080800 .* + 81010 000c0800 040c0800 00000000 00000000 .* + 81020 20100800 20200800 00040800 02080800 .* + 81030 080c0800 040c0800 .* diff --git a/ld/testsuite/ld-nios2/emit-relocs-1.ld b/ld/testsuite/ld-nios2/emit-relocs-1.ld new file mode 100644 index 0000000..1879ef4 --- /dev/null +++ b/ld/testsuite/ld-nios2/emit-relocs-1.ld @@ -0,0 +1,20 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x80000; + .text : { *(.text) } + + . = ALIGN (0x400); + .merge1 : { *(.merge1) } + + . = ALIGN (0x400); + .merge2 : { *(.merge2) } + + . = ALIGN (0x400); + .merge3 : { *(.merge3) } + + . = ALIGN (0x400); + .data : { *(.data) } + + /DISCARD/ : { *(*) } +} diff --git a/ld/testsuite/ld-nios2/emit-relocs-1a.s b/ld/testsuite/ld-nios2/emit-relocs-1a.s new file mode 100644 index 0000000..bf0a8a1 --- /dev/null +++ b/ld/testsuite/ld-nios2/emit-relocs-1a.s @@ -0,0 +1,24 @@ + .text + .align 4 + .globl _start +_start: + nop + + .section .merge1,"aMS",@progbits,1 +A: .string "utter" + + .section .merge2,"aMS",@progbits,1 +B: .string "tasting" + + .section .merge3,"aM",@progbits,4 +C: .4byte 0x100 +D: .4byte 0x200 + + .data + .align 4 +E: .4byte E + .4byte E + 0x1000 + .4byte A + .4byte B + .4byte C + .4byte D diff --git a/ld/testsuite/ld-nios2/emit-relocs-1b.s b/ld/testsuite/ld-nios2/emit-relocs-1b.s new file mode 100644 index 0000000..82229c1 --- /dev/null +++ b/ld/testsuite/ld-nios2/emit-relocs-1b.s @@ -0,0 +1,18 @@ + .section .merge1,"aMS",@progbits,1 +A: .string "flutter" + + .section .merge2,"aMS",@progbits,1 +B: .string "sting" + + .section .merge3,"aM",@progbits,4 +C: .4byte 0x300 +D: .4byte 0x200 + + .data + .align 4 +E: .4byte E + .4byte E + 0x1000 + .4byte A + .4byte B + .4byte C + .4byte D diff --git a/ld/testsuite/ld-nios2/gprel.d b/ld/testsuite/ld-nios2/gprel.d new file mode 100644 index 0000000..202aece --- /dev/null +++ b/ld/testsuite/ld-nios2/gprel.d @@ -0,0 +1,17 @@ +#name: NIOS2 gp-relative relocations +#source: gprel.s +#ld: +#objdump: -dr --prefix-addresses + +# Test the %gprel macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +[0-9a-f]+ <[^>]*> movui gp,[0-9]+ +[0-9a-f]+ <[^>]*> ldw at,-[0-9]+\(gp\) +[0-9a-f]+ <[^>]*> ldw r2,-[0-9]+\(gp\) +[0-9a-f]+ <[^>]*> ldb r3,-[0-9]+\(gp\) +[0-9a-f]+ <[^>]*> ldw at,-[0-9]+\(gp\) +[0-9a-f]+ <[^>]*> ldw r2,-[0-9]+\(gp\) +[0-9a-f]+ <[^>]*> ldb r3,-[0-9]+\(gp\) diff --git a/ld/testsuite/ld-nios2/gprel.s b/ld/testsuite/ld-nios2/gprel.s new file mode 100644 index 0000000..2414722 --- /dev/null +++ b/ld/testsuite/ld-nios2/gprel.s @@ -0,0 +1,29 @@ +.set noat + +.sdata + +sym1: +.long 0xdead +sym2: +.long 0xbeef +sym3: +.byte 0x7f + +.section .sbss, "w" +sym4: +.long 0 +sym5: +.long 0 +sym6: +.byte 0 + +.text +.global _start +_start: + movui gp, _gp + ldw r1, %gprel(sym1)(gp) + ldw r2, %gprel(sym2)(gp) + ldb r3, %gprel(sym3)(gp) + ldw r1, %gprel(sym4)(gp) + ldw r2, %gprel(sym5)(gp) + ldb r3, %gprel(sym6)(gp) diff --git a/ld/testsuite/ld-nios2/hilo16.d b/ld/testsuite/ld-nios2/hilo16.d new file mode 100644 index 0000000..c703413 --- /dev/null +++ b/ld/testsuite/ld-nios2/hilo16.d @@ -0,0 +1,13 @@ +#name: NIOS2 R_NIOS2_HI16,LO16,HIADJ16 +#source: hilo16.s +#source: hilo16_symbol.s +#ld: +#objdump: -dr --prefix-addresses + +# Test the %hi, %lo and %hiadi relocations +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +[0-9a-f]+ <[^>]*> addi at,at,-8531 +[0-9a-f]+ <[^>]*> addi at,at,-16657 +[0-9a-f]+ <[^>]*> addi at,at,-8530 diff --git a/ld/testsuite/ld-nios2/hilo16.s b/ld/testsuite/ld-nios2/hilo16.s new file mode 100644 index 0000000..47b404f1 --- /dev/null +++ b/ld/testsuite/ld-nios2/hilo16.s @@ -0,0 +1,10 @@ +# Test the %hi, lo and %hiadj relocations + +.set noat + +.text +.global _start +_start: + addi r1, r1, %hi(long_symbol) + addi r1, r1, %lo(long_symbol) + addi r1, r1, %hiadj(long_symbol) diff --git a/ld/testsuite/ld-nios2/hilo16_symbol.s b/ld/testsuite/ld-nios2/hilo16_symbol.s new file mode 100644 index 0000000..88fdddc --- /dev/null +++ b/ld/testsuite/ld-nios2/hilo16_symbol.s @@ -0,0 +1,3 @@ +.global long_symbol +.set long_symbol, 0xDEADBEEF + diff --git a/ld/testsuite/ld-nios2/imm5.d b/ld/testsuite/ld-nios2/imm5.d new file mode 100644 index 0000000..2640c9c --- /dev/null +++ b/ld/testsuite/ld-nios2/imm5.d @@ -0,0 +1,13 @@ +#name: NIOS2 R_NIOS2_IMM5 +#source: imm5.s +#source: imm5_symbol.s +#ld: +#objdump: -dr --prefix-addresses + +# Test the branch instructions. +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +[0-9a-f]+ <[^>]*> roli at,at,31 +[0-9a-f]+ <.[^>]*> Address 0x[0-9a-f]+ is out of bounds. + diff --git a/ld/testsuite/ld-nios2/imm5.s b/ld/testsuite/ld-nios2/imm5.s new file mode 100644 index 0000000..21bbfc3 --- /dev/null +++ b/ld/testsuite/ld-nios2/imm5.s @@ -0,0 +1,9 @@ +# Test the imm5 relocation + +.set noat +.text +.global _start +_start: + roli r1, r1, imm5 + + diff --git a/ld/testsuite/ld-nios2/imm5_symbol.s b/ld/testsuite/ld-nios2/imm5_symbol.s new file mode 100644 index 0000000..d988951 --- /dev/null +++ b/ld/testsuite/ld-nios2/imm5_symbol.s @@ -0,0 +1,4 @@ +.global imm5 +.text +.byte imm5 +.set imm5, 31 diff --git a/ld/testsuite/ld-nios2/nios2.exp b/ld/testsuite/ld-nios2/nios2.exp new file mode 100644 index 0000000..22080b4 --- /dev/null +++ b/ld/testsuite/ld-nios2/nios2.exp @@ -0,0 +1,7 @@ +if { ! [istarget nios2-*-*] } { + return +} + +foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.d]] { + run_dump_test [file rootname $test] +} diff --git a/ld/testsuite/ld-nios2/pcrel16.d b/ld/testsuite/ld-nios2/pcrel16.d new file mode 100644 index 0000000..d4dda2e --- /dev/null +++ b/ld/testsuite/ld-nios2/pcrel16.d @@ -0,0 +1,15 @@ +#name: NIOS2 R_NIOS2_PCREL16 +#source: pcrel16.s +#source: pcrel16_label.s +#ld: +#objdump: -dr --prefix-addresses + +# Test the relative branch relocations. +.*: +file format elf32-littlenios2 + +Disassembly of section .text: + +[0-9a-f]+ <[^>]*> br [0-9a-f]+ <ext_label> +[0-9a-f]+ <[^>]*> br [0-9a-f]+ <ext_label\+0x10> +[0-9a-f]+ <[^>]*> nop +[0-9a-f]+ <[^>]*> nop diff --git a/ld/testsuite/ld-nios2/pcrel16.s b/ld/testsuite/ld-nios2/pcrel16.s new file mode 100644 index 0000000..61c1c7e --- /dev/null +++ b/ld/testsuite/ld-nios2/pcrel16.s @@ -0,0 +1,8 @@ +# Test for pc-relative relocations +.set norelax +.text +.global _start +_start: + br ext_label + br ext_label + 16 + diff --git a/ld/testsuite/ld-nios2/pcrel16_label.s b/ld/testsuite/ld-nios2/pcrel16_label.s new file mode 100644 index 0000000..3a76612 --- /dev/null +++ b/ld/testsuite/ld-nios2/pcrel16_label.s @@ -0,0 +1,5 @@ +.text +ext_label: + nop + nop +.global ext_label diff --git a/ld/testsuite/ld-nios2/relax_callr.d b/ld/testsuite/ld-nios2/relax_callr.d new file mode 100644 index 0000000..7d40fe4 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_callr.d @@ -0,0 +1,24 @@ +#name: NIOS2 relax_callr +#as: -relax-all +#ld: --relax -Trelax_callr.ld +#source: relax_callr.s +#objdump: -dr --prefix-addresses +# Test relaxation of callr + +.*: +file format elf32-littlenios2 + +Disassembly of section text1: +00000000 <[^>]*> movhi at,2048 +00000004 <[^>]*> ori at,at,0 +00000008 <[^>]*> callr at +0000000c <[^>]*> movhi at,2048 +00000010 <[^>]*> ori at,at,20 +00000014 <[^>]*> callr at + +Disassembly of section text2: +08000000 <func> nop +08000004 <[^>]*> br 08000014 <func1> +08000008 <[^>]*> nop +0800000c <[^>]*> nop +08000010 <[^>]*> nop +08000014 <func1> nop diff --git a/ld/testsuite/ld-nios2/relax_callr.ld b/ld/testsuite/ld-nios2/relax_callr.ld new file mode 100644 index 0000000..bc02d40 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_callr.ld @@ -0,0 +1,11 @@ +/* Simple script for testing relaxation */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text1 0 : { *(text1) } + text2 0x08000000 : { *(text2) } +} diff --git a/ld/testsuite/ld-nios2/relax_callr.s b/ld/testsuite/ld-nios2/relax_callr.s new file mode 100644 index 0000000..b4cc2c4 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_callr.s @@ -0,0 +1,17 @@ +# relaxation test for callr + +.globl text1 +.section text1, "ax", @progbits + + call func + call func1 + +.section text2, "ax", @progbits +func: + nop + br func1 + nop + nop + nop +func1: + nop diff --git a/ld/testsuite/ld-nios2/relax_cjmp.d b/ld/testsuite/ld-nios2/relax_cjmp.d new file mode 100644 index 0000000..535c59d --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_cjmp.d @@ -0,0 +1,38 @@ +#name: NIOS2 relax_cjmp +#as: -relax-all +#ld: --relax -Trelax_jmp.ld +#source: relax_cjmp.s +#objdump: -dr --prefix-addresses + +# Test relaxation of conditional jumps + +.*: +file format elf32-littlenios2 + +Disassembly of section text2: +00000000 <[^>]*> bge r2,r3,00008000 <[^>]*> +00000004 <[^>]*> bge r2,r3,00000014 <[^>]*> +00000008 <[^>]*> movhi at,1 +0000000c <[^>]*> ori at,at,24 +00000010 <[^>]*> jmp at +00000014 <[^>]*> bge r3,r2,00000020 <sym> +00000018 <[^>]*> nop +0000001c <[^>]*> nop +00000020 <sym> nop + +Disassembly of section text1: +00008000 <[^>]*> beq r2,r3,00010000 <on_border> +00008004 <[^>]*> bne r2,r3,00008014 <[^>]*> +00008008 <[^>]*> movhi at,1 +0000800c <[^>]*> ori at,at,24 +00008010 <[^>]*> jmp at +00008014 <[^>]*> nop +00008018 <[^>]*> nop +#... +00010000 <on_border> bne r2,r3,00010018 <in_range> +00010004 <[^>]*> nop +00010008 <[^>]*> nop +0001000c <[^>]*> nop +00010010 <[^>]*> nop +00010014 <[^>]*> nop +00010018 <in_range> nop +#pass diff --git a/ld/testsuite/ld-nios2/relax_cjmp.s b/ld/testsuite/ld-nios2/relax_cjmp.s new file mode 100644 index 0000000..af00a1e --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_cjmp.s @@ -0,0 +1,32 @@ +# relaxing conditional jumps -- absolute + +.globl text1 +.section text1, "ax", @progbits + beq r2, r3, on_border + beq r2, r3, out_of_range + nop + nop + +.align 15 +on_border: + bne r2, r3, in_range + nop + nop + nop + nop + nop +out_of_range: +in_range: + nop + +.globl text2 +.section text2, "ax", @progbits + + bge r2, r3, text1 + blt r2, r3, out_of_range + ble r2, r3, sym + nop + nop +sym: + nop + diff --git a/ld/testsuite/ld-nios2/relax_jmp.ld b/ld/testsuite/ld-nios2/relax_jmp.ld new file mode 100644 index 0000000..df6c220 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_jmp.ld @@ -0,0 +1,11 @@ +/* Simple script for testing relaxation */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text2 0 : { *(text2) } + text1 0x8000 : { *(text1) } +} diff --git a/ld/testsuite/ld-nios2/relax_section.d b/ld/testsuite/ld-nios2/relax_section.d new file mode 100644 index 0000000..93980cd --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_section.d @@ -0,0 +1,35 @@ +#name: NIOS2 relax_section +#as: -relax-section +#ld: --relax -Trelax_jmp.ld +#source: relax_section.s +#objdump: -dr --prefix-addresses + +# Test relaxation of section + +.*: +file format elf32-littlenios2 + +Disassembly of section text1: +00008000 <[^>]*> bne r2,r3,00008010 <[^>]*> +00008004 <[^>]*> nextpc at +00008008 <[^>]*> addi at,at,32764 +0000800c <[^>]*> jmp at +00008010 <[^>]*> bge r2,r3,00008024 <[^>]*> +00008014 <[^>]*> nextpc at +00008018 <[^>]*> addi at,at,32767 +0000801c <[^>]*> addi at,at,9 +00008020 <[^>]*> jmp at +00008024 <[^>]*> bne r2,r3,00008030 <in_range> +00008028 <[^>]*> nop +0000802c <[^>]*> nop +00008030 <in_range> nop +#... +00010000 <[^>]*> br 00008030 <in_range> +00010004 <just_out_of_range> nop +00010008 <[^>]*> nop +0001000c <[^>]*> nop +00010010 <[^>]*> nop +00010014 <[^>]*> nop +00010018 <[^>]*> nop +0001001c <[^>]*> nop +00010020 <farther_out_of_range> nop +#pass diff --git a/ld/testsuite/ld-nios2/relax_section.s b/ld/testsuite/ld-nios2/relax_section.s new file mode 100644 index 0000000..0e803d1 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_section.s @@ -0,0 +1,23 @@ +# relaxing conditional and unconditional jumps -- pc-relative + +.globl text1 +.section text1, "ax", @progbits + beq r2, r3, just_out_of_range + blt r2, r3, farther_out_of_range + bne r2, r3, in_range + nop + nop +in_range: + nop +.align 15 + br in_range +just_out_of_range: + nop + nop + nop + nop + nop + nop + nop +farther_out_of_range: + nop diff --git a/ld/testsuite/ld-nios2/relax_ujmp.d b/ld/testsuite/ld-nios2/relax_ujmp.d new file mode 100644 index 0000000..68313c1 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_ujmp.d @@ -0,0 +1,32 @@ +#name: NIOS2 relax_ujmp +#as: -relax-all +#ld: --relax -Trelax_jmp.ld +#source: relax_ujmp.s +#objdump: -dr --prefix-addresses + +# Test relaxation of unconditional jumps + +.*: +file format elf32-littlenios2 + +Disassembly of section text2: +00000000 <[^>]*> br 00008000 <[^>]*> +00000004 <[^>]*> movhi at,1 +00000008 <[^>]*> ori at,at,16 +0000000c <[^>]*> jmp at +00000010 <[^>]*> br 0000001c <sym> +00000014 <[^>]*> nop +00000018 <[^>]*> nop +0000001c <sym> nop + +Disassembly of section text1: +00008000 <[^>]*> br 00010000 <on_border> +00008004 <[^>]*> movhi at,1 +00008008 <[^>]*> ori at,at,16 +0000800c <[^>]*> jmp at +#... +00010000 <on_border> br 00010010 <in_range> +00010004 <[^>]*> nop +00010008 <[^>]*> nop +0001000c <[^>]*> nop +00010010 <in_range> nop +#pass diff --git a/ld/testsuite/ld-nios2/relax_ujmp.s b/ld/testsuite/ld-nios2/relax_ujmp.s new file mode 100644 index 0000000..8982d73 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_ujmp.s @@ -0,0 +1,37 @@ +# relaxing unconditional jumps + +.globl text1 +.section text1, "ax", @progbits + + br on_border + br out_of_range + nop + nop + + +.align 15 +# nop +# nop +on_border: + br in_range + nop + nop + nop +out_of_range: +in_range: + nop + +.globl text2 +.section text2, "ax", @progbits + + br text1 + br out_of_range + br sym + nop + nop +sym: + nop + + + + diff --git a/ld/testsuite/ld-nios2/reloc.d b/ld/testsuite/ld-nios2/reloc.d new file mode 100644 index 0000000..cb2959d --- /dev/null +++ b/ld/testsuite/ld-nios2/reloc.d @@ -0,0 +1,10 @@ +#name: NIOS2 R_NIOS2_BFD_RELOC_XX +#source: reloc.s +#source: reloc_symbol.s +#ld: +#objdump: -s + +.*: +file format elf32-littlenios2 + +Contents of section .text: + [0-9a-f]+ fa00cefa efbeadde facefaef beadde00 ................ diff --git a/ld/testsuite/ld-nios2/reloc.s b/ld/testsuite/ld-nios2/reloc.s new file mode 100644 index 0000000..2d555c3 --- /dev/null +++ b/ld/testsuite/ld-nios2/reloc.s @@ -0,0 +1,9 @@ +# Test for Nios II 32-bit, 16 and 8-bit relocations + +.global byte_sym +.global short_sym +.global long_sym + +.set byte_sym, 0xFA +.set short_sym, 0xFACE +.set long_sym, 0xDEADBEEF diff --git a/ld/testsuite/ld-nios2/reloc_symbol.s b/ld/testsuite/ld-nios2/reloc_symbol.s new file mode 100644 index 0000000..fa7ac95 --- /dev/null +++ b/ld/testsuite/ld-nios2/reloc_symbol.s @@ -0,0 +1,24 @@ +.text +.global _start +_start: + +# byte aligned +.align 0 +.byte byte_sym + +# short aligned +.align 1 +.short short_sym + +# word aligned +.align 2 +.long long_sym + +# now lets try some unaligned words and halfwords +.byte byte_sym +.2byte short_sym +.4byte long_sym + +#.align 2 +#nop + diff --git a/ld/testsuite/ld-nios2/s16.d b/ld/testsuite/ld-nios2/s16.d new file mode 100644 index 0000000..6257e18 --- /dev/null +++ b/ld/testsuite/ld-nios2/s16.d @@ -0,0 +1,12 @@ +#name: NIOS2 R_NIOS2_S16 +#source: s16.s +#source: s16_symbol.s +#ld: +#objdump: -s + +# Test the signed 16-bit relocations. +.*: +file format elf32-littlenios2 + +Contents of section .text: + [0-9a-f]+ 04004408 04006008 c4ff5f08 44004808 ..D...`..._.D.H. + [0-9a-f]+ 44004008 D.@. diff --git a/ld/testsuite/ld-nios2/s16.s b/ld/testsuite/ld-nios2/s16.s new file mode 100644 index 0000000..df13efa --- /dev/null +++ b/ld/testsuite/ld-nios2/s16.s @@ -0,0 +1,16 @@ +# Test for Nios II 32-bit, 16 and 8-bit relocations + +.set noat +.set some_other_sym, 0x1000 +.text +.global _start +_start: +# signed 16-bit relocation + addi r1, r1, some_sym + addi r1, r1, min + addi r1, r1, max + addi r1, r1, some_sym + some_other_sym + 1 + addi r1, r1, some_sym - some_other_sym + 1 + + + diff --git a/ld/testsuite/ld-nios2/s16_symbol.s b/ld/testsuite/ld-nios2/s16_symbol.s new file mode 100644 index 0000000..3902177 --- /dev/null +++ b/ld/testsuite/ld-nios2/s16_symbol.s @@ -0,0 +1,10 @@ +.global some_sym +.global some_other_sym +.global min +.global max + +.set max, 0x7fff +.set min, -0x8000 +.set some_sym, 0x1000 + + diff --git a/ld/testsuite/ld-nios2/u16.d b/ld/testsuite/ld-nios2/u16.d new file mode 100644 index 0000000..7d1df05 --- /dev/null +++ b/ld/testsuite/ld-nios2/u16.d @@ -0,0 +1,12 @@ +#name: NIOS2 R_NIOS2_U16 +#source: u16.s +#source: u16_symbol.s +#ld: +#objdump: -s + +# Test the unsigned 16-bit relocations. +.*: +file format elf32-littlenios2 + +Contents of section .text: + [0-9a-f]+ 0c004408 0c004008 ccff7f08 4c004808 ..D...@.....L.H. + [0-9a-f]+ 4c004008 L.@. diff --git a/ld/testsuite/ld-nios2/u16.s b/ld/testsuite/ld-nios2/u16.s new file mode 100644 index 0000000..b890682 --- /dev/null +++ b/ld/testsuite/ld-nios2/u16.s @@ -0,0 +1,16 @@ +# Test for Nios II 32-bit, 16 and 8-bit relocations + +.set noat +.set some_other_sym, 0x1000 +.text +.global _start +_start: +# unsigned 16-bit relocation + andi r1, r1, some_sym + andi r1, r1, min + andi r1, r1, max + andi r1, r1, some_sym + some_other_sym + 1 + andi r1, r1, some_sym - some_other_sym + 1 + + + diff --git a/ld/testsuite/ld-nios2/u16_symbol.s b/ld/testsuite/ld-nios2/u16_symbol.s new file mode 100644 index 0000000..518b4de --- /dev/null +++ b/ld/testsuite/ld-nios2/u16_symbol.s @@ -0,0 +1,9 @@ +.global some_sym +.global min +.global max + +.set max, 0xffff +.set min, 0 +.set some_sym, 0x1000 + + diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp index a3898c9..365b988 100644 --- a/ld/testsuite/ld-plugin/lto.exp +++ b/ld/testsuite/ld-plugin/lto.exp @@ -265,7 +265,9 @@ set lto_run_elf_tests { run_cc_link_tests $lto_link_tests -if { [is_elf_format] } { +# Restrict these to ELF targets that support shared libs and PIC. +if { [is_elf_format] + && [run_host_cmd_yesno $CC "-shared -fPIC $srcdir/$subdir/dummy.c -o tmpdir/t.so"] } { run_cc_link_tests $lto_link_elf_tests } @@ -295,6 +297,11 @@ remote_exec host "mv" "tmpdir/dump tmpdir/lto-5.o" run_cc_link_tests $lto_link_symbol_tests +# The following tests require running the executable generated by ld. +if ![isnative] { + return +} + run_ld_link_exec_tests [] $lto_run_tests if { [is_elf_format] } { diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index a3d33df..11f1470 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,18 @@ +2013-02-06 Sandra Loosemore <sandra@codesourcery.com> + Andrew Jenner <andrew@codesourcery.com> + + Based on patches from Altera Corporation. + + * Makefile.am (TARGET_LIBOPCODES_CFILES): Add nios2-dis.c and + nios2-opc.c. + * Makefile.in: Regenerated. + * configure.in: Add case for bfd_nios2_arch. + * configure: Regenerated. + * disassemble.c (ARCH_nios2): Define. + (disassembler): Add case for bfd_arch_nios2. + * nios2-dis.c: New file. + * nios2-opc.c: New file. + 2013-02-04 Alan Modra <amodra@gmail.com> * po/POTFILES.in: Regenerate. diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index e161490..4a63810 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -205,6 +205,8 @@ TARGET_LIBOPCODES_CFILES = \ mt-dis.c \ mt-ibld.c \ mt-opc.c \ + nios2-dis.c \ + nios2-opc.c \ ns32k-dis.c \ openrisc-asm.c \ openrisc-desc.c \ diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index c8eae65..1825bd0 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -477,6 +477,8 @@ TARGET_LIBOPCODES_CFILES = \ mt-dis.c \ mt-ibld.c \ mt-opc.c \ + nios2-dis.c \ + nios2-opc.c \ ns32k-dis.c \ openrisc-asm.c \ openrisc-desc.c \ @@ -874,6 +876,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-ibld.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-opc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nios2-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nios2-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns32k-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openrisc-asm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openrisc-desc.Plo@am__quote@ diff --git a/opcodes/configure b/opcodes/configure index 4a8ff54..7e4b558 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -12540,6 +12540,7 @@ if test x${all_targets} = xfalse ; then bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; bfd_msp430_arch) ta="$ta msp430-dis.lo" ;; + bfd_nios2_arch) ta="$ta nios2-dis.lo nios2-opc.lo" ;; bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; bfd_openrisc_arch) ta="$ta openrisc-asm.lo openrisc-desc.lo openrisc-dis.lo openrisc-ibld.lo openrisc-opc.lo" using_cgen=yes ;; bfd_or32_arch) ta="$ta or32-dis.lo or32-opc.lo" using_cgen=yes ;; diff --git a/opcodes/configure.in b/opcodes/configure.in index 5f9b3a3..7912b85 100644 --- a/opcodes/configure.in +++ b/opcodes/configure.in @@ -293,6 +293,7 @@ if test x${all_targets} = xfalse ; then bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; bfd_msp430_arch) ta="$ta msp430-dis.lo" ;; + bfd_nios2_arch) ta="$ta nios2-dis.lo nios2-opc.lo" ;; bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; bfd_openrisc_arch) ta="$ta openrisc-asm.lo openrisc-desc.lo openrisc-dis.lo openrisc-ibld.lo openrisc-opc.lo" using_cgen=yes ;; bfd_or32_arch) ta="$ta or32-dis.lo or32-opc.lo" using_cgen=yes ;; diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index 2073a5e..55a44ec 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -67,6 +67,7 @@ #define ARCH_moxie #define ARCH_mt #define ARCH_msp430 +#define ARCH_nios2 #define ARCH_ns32k #define ARCH_openrisc #define ARCH_or32 @@ -338,6 +339,14 @@ disassembler (abfd) disassemble = print_insn_mn10300; break; #endif +#ifdef ARCH_nios2 + case bfd_arch_nios2: + if (bfd_big_endian (abfd)) + disassemble = print_insn_big_nios2; + else + disassemble = print_insn_little_nios2; + break; +#endif #ifdef ARCH_openrisc case bfd_arch_openrisc: disassemble = print_insn_openrisc; diff --git a/opcodes/nios2-dis.c b/opcodes/nios2-dis.c new file mode 100644 index 0000000..ef7a5f9 --- /dev/null +++ b/opcodes/nios2-dis.c @@ -0,0 +1,423 @@ +/* Altera Nios II disassemble routines + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "dis-asm.h" +#include "opcode/nios2.h" +#include "libiberty.h" +#include <string.h> +#include <assert.h> + +/* No symbol table is available when this code runs out in an embedded + system as when it is used for disassembler support in a monitor. */ +#if !defined(EMBEDDED_ENV) +#define SYMTAB_AVAILABLE 1 +#include "elf-bfd.h" +#include "elf/nios2.h" +#endif + +/* Length of Nios II instruction in bytes. */ +#define INSNLEN 4 + +/* Data structures used by the opcode hash table. */ +typedef struct _nios2_opcode_hash +{ + const struct nios2_opcode *opcode; + struct _nios2_opcode_hash *next; +} nios2_opcode_hash; + +static bfd_boolean nios2_hash_init = 0; +static nios2_opcode_hash *nios2_hash[(OP_MASK_OP) + 1]; + +/* Separate hash table for pseudo-ops. */ +static nios2_opcode_hash *nios2_ps_hash[(OP_MASK_OP) + 1]; + +/* Function to initialize the opcode hash table. */ +static void +nios2_init_opcode_hash (void) +{ + unsigned int i; + register const struct nios2_opcode *op; + + for (i = 0; i <= OP_MASK_OP; ++i) + nios2_hash[0] = NULL; + for (i = 0; i <= OP_MASK_OP; i++) + for (op = nios2_opcodes; op < &nios2_opcodes[NUMOPCODES]; op++) + { + nios2_opcode_hash *new_hash; + nios2_opcode_hash **bucket = NULL; + + if ((op->pinfo & NIOS2_INSN_MACRO) == NIOS2_INSN_MACRO) + { + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP) + && (op->pinfo & (NIOS2_INSN_MACRO_MOV | NIOS2_INSN_MACRO_MOVI) + & 0x7fffffff)) + bucket = &(nios2_ps_hash[i]); + } + else if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) + bucket = &(nios2_hash[i]); + + if (bucket) + { + new_hash = + (nios2_opcode_hash *) malloc (sizeof (nios2_opcode_hash)); + if (new_hash == NULL) + { + fprintf (stderr, + "error allocating memory...broken disassembler\n"); + abort (); + } + new_hash->opcode = op; + new_hash->next = NULL; + while (*bucket) + bucket = &((*bucket)->next); + *bucket = new_hash; + } + } + nios2_hash_init = 1; +#ifdef DEBUG_HASHTABLE + for (i = 0; i <= OP_MASK_OP; ++i) + { + nios2_opcode_hash *tmp_hash = nios2_hash[i]; + printf ("index: 0x%02X ops: ", i); + while (tmp_hash != NULL) + { + printf ("%s ", tmp_hash->opcode->name); + tmp_hash = tmp_hash->next; + } + printf ("\n"); + } + + for (i = 0; i <= OP_MASK_OP; ++i) + { + nios2_opcode_hash *tmp_hash = nios2_ps_hash[i]; + printf ("index: 0x%02X ops: ", i); + while (tmp_hash != NULL) + { + printf ("%s ", tmp_hash->opcode->name); + tmp_hash = tmp_hash->next; + } + printf ("\n"); + } +#endif /* DEBUG_HASHTABLE */ +} + +/* Return a pointer to an nios2_opcode struct for a given instruction + opcode, or NULL if there is an error. */ +const struct nios2_opcode * +nios2_find_opcode_hash (unsigned long opcode) +{ + nios2_opcode_hash *entry; + + /* Build a hash table to shorten the search time. */ + if (!nios2_hash_init) + nios2_init_opcode_hash (); + + /* First look in the pseudo-op hashtable. */ + for (entry = nios2_ps_hash[(opcode >> OP_SH_OP) & OP_MASK_OP]; + entry; entry = entry->next) + if (entry->opcode->match == (opcode & entry->opcode->mask)) + return entry->opcode; + + /* Otherwise look in the main hashtable. */ + for (entry = nios2_hash[(opcode >> OP_SH_OP) & OP_MASK_OP]; + entry; entry = entry->next) + if (entry->opcode->match == (opcode & entry->opcode->mask)) + return entry->opcode; + + return NULL; +} + +/* There are 32 regular registers, 32 coprocessor registers, + and 32 control registers. */ +#define NUMREGNAMES 32 + +/* Return a pointer to the base of the coprocessor register name array. */ +static struct nios2_reg * +nios2_coprocessor_regs (void) +{ + static struct nios2_reg *cached = NULL; + + if (!cached) + { + int i; + for (i = NUMREGNAMES; i < nios2_num_regs; i++) + if (!strcmp (nios2_regs[i].name, "c0")) + { + cached = nios2_regs + i; + break; + } + assert (cached); + } + return cached; +} + +/* Return a pointer to the base of the control register name array. */ +static struct nios2_reg * +nios2_control_regs (void) +{ + static struct nios2_reg *cached = NULL; + + if (!cached) + { + int i; + for (i = NUMREGNAMES; i < nios2_num_regs; i++) + if (!strcmp (nios2_regs[i].name, "status")) + { + cached = nios2_regs + i; + break; + } + assert (cached); + } + return cached; +} + +/* The function nios2_print_insn_arg uses the character pointed + to by ARGPTR to determine how it print the next token or separator + character in the arguments to an instruction. */ +static int +nios2_print_insn_arg (const char *argptr, + unsigned long opcode, bfd_vma address, + disassemble_info *info) +{ + unsigned long i = 0; + struct nios2_reg *reg_base; + + switch (*argptr) + { + case ',': + case '(': + case ')': + (*info->fprintf_func) (info->stream, "%c", *argptr); + break; + case 'd': + i = GET_INSN_FIELD (RRD, opcode); + + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM + && GET_INSN_FIELD (CUSTOM_C, opcode) == 0) + reg_base = nios2_coprocessor_regs (); + else + reg_base = nios2_regs; + + if (i < NUMREGNAMES) + (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); + else + (*info->fprintf_func) (info->stream, "unknown"); + break; + case 's': + i = GET_INSN_FIELD (RRS, opcode); + + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM + && GET_INSN_FIELD (CUSTOM_A, opcode) == 0) + reg_base = nios2_coprocessor_regs (); + else + reg_base = nios2_regs; + + if (i < NUMREGNAMES) + (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); + else + (*info->fprintf_func) (info->stream, "unknown"); + break; + case 't': + i = GET_INSN_FIELD (RRT, opcode); + + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM + && GET_INSN_FIELD (CUSTOM_B, opcode) == 0) + reg_base = nios2_coprocessor_regs (); + else + reg_base = nios2_regs; + + if (i < NUMREGNAMES) + (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); + else + (*info->fprintf_func) (info->stream, "unknown"); + break; + case 'i': + /* 16-bit signed immediate. */ + i = (signed) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16; + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'u': + /* 16-bit unsigned immediate. */ + i = GET_INSN_FIELD (IMM16, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'o': + /* 16-bit signed immediate address offset. */ + i = (signed) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16; + address = address + 4 + i; + (*info->print_address_func) (address, info); + break; + case 'p': + /* 5-bit unsigned immediate. */ + i = GET_INSN_FIELD (CACHE_OPX, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'j': + /* 5-bit unsigned immediate. */ + i = GET_INSN_FIELD (IMM5, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'l': + /* 8-bit unsigned immediate. */ + /* FIXME - not yet implemented */ + i = GET_INSN_FIELD (CUSTOM_N, opcode); + (*info->fprintf_func) (info->stream, "%lu", i); + break; + case 'm': + /* 26-bit unsigned immediate. */ + i = GET_INSN_FIELD (IMM26, opcode); + /* This translates to an address because it's only used in call + instructions. */ + address = (address & 0xf0000000) | (i << 2); + (*info->print_address_func) (address, info); + break; + case 'c': + /* Control register index. */ + i = GET_INSN_FIELD (IMM5, opcode); + reg_base = nios2_control_regs (); + (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); + break; + case 'b': + i = GET_INSN_FIELD (IMM5, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + default: + (*info->fprintf_func) (info->stream, "unknown"); + break; + } + return 0; +} + +/* nios2_disassemble does all the work of disassembling a Nios II + instruction opcode. */ +static int +nios2_disassemble (bfd_vma address, unsigned long opcode, + disassemble_info *info) +{ + const struct nios2_opcode *op; + + info->bytes_per_line = INSNLEN; + info->bytes_per_chunk = INSNLEN; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + /* Find the major opcode and use this to disassemble + the instruction and its arguments. */ + op = nios2_find_opcode_hash (opcode); + + if (op != NULL) + { + bfd_boolean is_nop = FALSE; + if (op->pinfo == NIOS2_INSN_MACRO_MOV) + { + /* Check for mov r0, r0 and change to nop. */ + int dst, src; + dst = GET_INSN_FIELD (RRD, opcode); + src = GET_INSN_FIELD (RRS, opcode); + if (dst == 0 && src == 0) + { + (*info->fprintf_func) (info->stream, "nop"); + is_nop = TRUE; + } + else + (*info->fprintf_func) (info->stream, "%s", op->name); + } + else + (*info->fprintf_func) (info->stream, "%s", op->name); + + if (!is_nop) + { + const char *argstr = op->args; + if (argstr != NULL && *argstr != '\0') + { + (*info->fprintf_func) (info->stream, "\t"); + while (*argstr != '\0') + { + nios2_print_insn_arg (argstr, opcode, address, info); + ++argstr; + } + } + } + } + else + { + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream, "0x%lx", opcode); + } + /* Tell the caller how far to advance the program counter. */ + return INSNLEN; +} + + +/* print_insn_nios2 is the main disassemble function for Nios II. + The function diassembler(abfd) (source in disassemble.c) returns a + pointer to this either print_insn_big_nios2 or + print_insn_little_nios2, which in turn call this function when the + bfd machine type is Nios II. print_insn_nios2 reads the + instruction word at the address given, and prints the disassembled + instruction on the stream info->stream using info->fprintf_func. */ + +static int +print_insn_nios2 (bfd_vma address, disassemble_info *info, + enum bfd_endian endianness) +{ + bfd_byte buffer[INSNLEN]; + int status; + + status = (*info->read_memory_func) (address, buffer, INSNLEN, info); + if (status == 0) + { + unsigned long insn; + if (endianness == BFD_ENDIAN_BIG) + insn = (unsigned long) bfd_getb32 (buffer); + else + insn = (unsigned long) bfd_getl32 (buffer); + status = nios2_disassemble (address, insn, info); + } + else + { + (*info->memory_error_func) (status, address, info); + status = -1; + } + return status; +} + +/* These two functions are the main entry points, accessed from + disassemble.c. */ +int +print_insn_big_nios2 (bfd_vma address, disassemble_info *info) +{ + return print_insn_nios2 (address, info, BFD_ENDIAN_BIG); +} + +int +print_insn_little_nios2 (bfd_vma address, disassemble_info *info) +{ + return print_insn_nios2 (address, info, BFD_ENDIAN_LITTLE); +} diff --git a/opcodes/nios2-opc.c b/opcodes/nios2-opc.c new file mode 100644 index 0000000..d5094ac --- /dev/null +++ b/opcodes/nios2-opc.c @@ -0,0 +1,410 @@ +/* Altera Nios II opcode list. + Copyright (C) 2012, 2013 Free Software Foundation, Inc. + Contributed by Nigel Gray (ngray@altera.com). + Contributed by Mentor Graphics, Inc. + + 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include <stdio.h> +#include "opcode/nios2.h" + +/* Register string table */ + +const struct nios2_reg nios2_builtin_regs[] = { + /* Standard register names. */ + {"zero", 0}, + {"at", 1}, /* assembler temporary */ + {"r2", 2}, + {"r3", 3}, + {"r4", 4}, + {"r5", 5}, + {"r6", 6}, + {"r7", 7}, + {"r8", 8}, + {"r9", 9}, + {"r10", 10}, + {"r11", 11}, + {"r12", 12}, + {"r13", 13}, + {"r14", 14}, + {"r15", 15}, + {"r16", 16}, + {"r17", 17}, + {"r18", 18}, + {"r19", 19}, + {"r20", 20}, + {"r21", 21}, + {"r22", 22}, + {"r23", 23}, + {"et", 24}, + {"bt", 25}, + {"gp", 26}, /* global pointer */ + {"sp", 27}, /* stack pointer */ + {"fp", 28}, /* frame pointer */ + {"ea", 29}, /* exception return address */ + {"ba", 30}, /* breakpoint return address */ + {"ra", 31}, /* return address */ + + /* Alternative names for special registers. */ + {"r0", 0}, + {"r1", 1}, + {"r24", 24}, + {"r25", 25}, + {"r26", 26}, + {"r27", 27}, + {"r28", 28}, + {"r29", 29}, + {"r30", 30}, + {"r31", 31}, + + /* Control register names. */ + {"status", 0}, + {"estatus", 1}, + {"bstatus", 2}, + {"ienable", 3}, + {"ipending", 4}, + {"cpuid", 5}, + {"ctl6", 6}, + {"exception", 7}, + {"pteaddr", 8}, + {"tlbacc", 9}, + {"tlbmisc", 10}, + {"fstatus", 11}, + {"badaddr", 12}, + {"config", 13}, + {"mpubase", 14}, + {"mpuacc", 15}, + {"ctl16", 16}, + {"ctl17", 17}, + {"ctl18", 18}, + {"ctl19", 19}, + {"ctl20", 20}, + {"ctl21", 21}, + {"ctl22", 22}, + {"ctl23", 23}, + {"ctl24", 24}, + {"ctl25", 25}, + {"ctl26", 26}, + {"ctl27", 27}, + {"ctl28", 28}, + {"ctl29", 29}, + {"ctl30", 30}, + {"ctl31", 31}, + + /* Alternative names for special control registers. */ + {"ctl0", 0}, + {"ctl1", 1}, + {"ctl2", 2}, + {"ctl3", 3}, + {"ctl4", 4}, + {"ctl5", 5}, + {"ctl7", 7}, + {"ctl8", 8}, + {"ctl9", 9}, + {"ctl10", 10}, + {"ctl11", 11}, + {"ctl12", 12}, + {"ctl13", 13}, + {"ctl14", 14}, + {"ctl15", 15}, + + /* Coprocessor register names. */ + {"c0", 0}, + {"c1", 1}, + {"c2", 2}, + {"c3", 3}, + {"c4", 4}, + {"c5", 5}, + {"c6", 6}, + {"c7", 7}, + {"c8", 8}, + {"c9", 9}, + {"c10", 10}, + {"c11", 11}, + {"c12", 12}, + {"c13", 13}, + {"c14", 14}, + {"c15", 15}, + {"c16", 16}, + {"c17", 17}, + {"c18", 18}, + {"c19", 19}, + {"c20", 20}, + {"c21", 21}, + {"c22", 22}, + {"c23", 23}, + {"c24", 24}, + {"c25", 25}, + {"c26", 26}, + {"c27", 27}, + {"c28", 28}, + {"c29", 29}, + {"c30", 30}, + {"c31", 31}, +}; + +#define NIOS2_NUM_REGS \ + ((sizeof nios2_builtin_regs) / (sizeof (nios2_builtin_regs[0]))) +const int nios2_num_builtin_regs = NIOS2_NUM_REGS; + +/* This is not const in order to allow for dynamic extensions to the + built-in instruction set. */ +struct nios2_reg *nios2_regs = (struct nios2_reg *) nios2_builtin_regs; +int nios2_num_regs = NIOS2_NUM_REGS; +#undef NIOS2_NUM_REGS + +/* This is the opcode table used by the Nios II GNU as, disassembler + and GDB. */ +const struct nios2_opcode nios2_builtin_opcodes[] = +{ + /* { name, args, args_test, num_args, + match, mask, pinfo, overflow_msg } */ + {"add", "d,s,t", "d,s,t,E", 3, + OP_MATCH_ADD, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"addi", "t,s,i", "t,s,i,E", 3, + OP_MATCH_ADDI, OP_MASK_IOP, NIOS2_INSN_ADDI, signed_immed16_overflow}, + {"subi", "t,s,i", "t,s,i,E", 3, + OP_MATCH_ADDI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow}, + {"and", "d,s,t", "d,s,t,E", 3, + OP_MATCH_AND, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"andhi", "t,s,u", "t,s,u,E", 3, + OP_MATCH_ANDHI, OP_MASK_IOP, 0, unsigned_immed16_overflow}, + {"andi", "t,s,u", "t,s,u,E", 3, + OP_MATCH_ANDI, OP_MASK_IOP, NIOS2_INSN_ANDI, unsigned_immed16_overflow}, + {"beq", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BEQ, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"bge", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BGE, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"bgeu", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BGEU, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"bgt", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BLT, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, + branch_target_overflow}, + {"bgtu", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BLTU, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, + branch_target_overflow}, + {"ble", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BGE, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, + branch_target_overflow}, + {"bleu", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BGEU, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, + branch_target_overflow}, + {"blt", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BLT, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"bltu", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BLTU, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"bne", "s,t,o", "s,t,o,E", 3, + OP_MATCH_BNE, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow}, + {"br", "o", "o,E", 1, + OP_MATCH_BR, OP_MASK_IOP, NIOS2_INSN_UBRANCH, branch_target_overflow}, + {"break", "b", "b,E", 1, + OP_MATCH_BREAK, OP_MASK_BREAK, 0, no_overflow}, + {"bret", "", "E", 0, + OP_MATCH_BRET, OP_MASK, 0, no_overflow}, + {"flushd", "i(s)", "i(s)E", 2, + OP_MATCH_FLUSHD, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"flushda", "i(s)", "i(s)E", 2, + OP_MATCH_FLUSHDA, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"flushi", "s", "s,E", 1, + OP_MATCH_FLUSHI, OP_MASK_FLUSHI, 0, no_overflow}, + {"flushp", "", "E", 0, + OP_MATCH_FLUSHP, OP_MASK, 0, no_overflow}, + {"initd", "i(s)", "i(s)E", 2, + OP_MATCH_INITD, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"initda", "i(s)", "i(s)E", 2, + OP_MATCH_INITDA, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"initi", "s", "s,E", 1, + OP_MATCH_INITI, OP_MASK_INITI, 0, no_overflow}, + {"call", "m", "m,E", 1, + OP_MATCH_CALL, OP_MASK_IOP, NIOS2_INSN_CALL, call_target_overflow}, + {"callr", "s", "s,E", 1, + OP_MATCH_CALLR, OP_MASK_CALLR, 0, no_overflow}, + {"cmpeq", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPEQ, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmpeqi", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPEQI, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"cmpge", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPGE, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmpgei", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPGEI, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"cmpgeu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPGEU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmpgeui", "t,s,u", "t,s,u,E", 3, + OP_MATCH_CMPGEUI, OP_MASK_IOP, 0, unsigned_immed16_overflow}, + {"cmpgt", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPLT, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow}, + {"cmpgti", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPGEI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow}, + {"cmpgtu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPLTU, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow}, + {"cmpgtui", "t,s,u", "t,s,u,E", 3, + OP_MATCH_CMPGEUI, OP_MASK_IOP, NIOS2_INSN_MACRO, unsigned_immed16_overflow}, + {"cmple", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPGE, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow}, + {"cmplei", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPLTI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow}, + {"cmpleu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPGEU, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow}, + {"cmpleui", "t,s,u", "t,s,u,E", 3, + OP_MATCH_CMPLTUI, OP_MASK_IOP, NIOS2_INSN_MACRO, unsigned_immed16_overflow}, + {"cmplt", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPLT, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmplti", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPLTI, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"cmpltu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPLTU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmpltui", "t,s,u", "t,s,u,E", 3, + OP_MATCH_CMPLTUI, OP_MASK_IOP, 0, unsigned_immed16_overflow}, + {"cmpne", "d,s,t", "d,s,t,E", 3, + OP_MATCH_CMPNE, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"cmpnei", "t,s,i", "t,s,i,E", 3, + OP_MATCH_CMPNEI, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"div", "d,s,t", "d,s,t,E", 3, + OP_MATCH_DIV, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"divu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_DIVU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"jmp", "s", "s,E", 1, + OP_MATCH_JMP, OP_MASK_JMP, 0, no_overflow}, + {"jmpi", "m", "m,E", 1, + OP_MATCH_JMPI, OP_MASK_IOP, 0, no_overflow}, + {"ldb", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDB, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldbio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDBIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldbu", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDBU, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldbuio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDBUIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldh", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDH, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldhio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDHIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldhu", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDHU, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldhuio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDHUIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldl", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDL, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldw", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDW, OP_MASK_IOP, 0, address_offset_overflow}, + {"ldwio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_LDWIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"mov", "d,s", "d,s,E", 2, + OP_MATCH_ADD, OP_MASK_RRT|OP_MASK_ROPX|OP_MASK_ROP, NIOS2_INSN_MACRO_MOV, + no_overflow}, + {"movhi", "t,u", "t,u,E", 2, + OP_MATCH_ORHI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, + unsigned_immed16_overflow}, + {"movui", "t,u", "t,u,E", 2, + OP_MATCH_ORI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, + unsigned_immed16_overflow}, + {"movi", "t,i", "t,i,E", 2, + OP_MATCH_ADDI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, + signed_immed16_overflow}, + /* movia expands to two instructions so there is no mask or match */ + {"movia", "t,o", "t,o,E", 2, + OP_MATCH_ORHI, OP_MASK_IOP, NIOS2_INSN_MACRO_MOVIA, no_overflow}, + {"mul", "d,s,t", "d,s,t,E", 3, + OP_MATCH_MUL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"muli", "t,s,i", "t,s,i,E", 3, + OP_MATCH_MULI, OP_MASK_IOP, 0, signed_immed16_overflow}, + {"mulxss", "d,s,t", "d,s,t,E", 3, + OP_MATCH_MULXSS, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"mulxsu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_MULXSU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"mulxuu", "d,s,t", "d,s,t,E", 3, + OP_MATCH_MULXUU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"nextpc", "d", "d,E", 1, + OP_MATCH_NEXTPC, OP_MASK_NEXTPC, 0, no_overflow}, + {"nop", "", "E", 0, + OP_MATCH_ADD, OP_MASK, NIOS2_INSN_MACRO_MOV, no_overflow}, + {"nor", "d,s,t", "d,s,t,E", 3, + OP_MATCH_NOR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"or", "d,s,t", "d,s,t,E", 3, + OP_MATCH_OR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"orhi", "t,s,u", "t,s,u,E", 3, + OP_MATCH_ORHI, OP_MASK_IOP, 0, unsigned_immed16_overflow}, + {"ori", "t,s,u", "t,s,u,E", 3, + OP_MATCH_ORI, OP_MASK_IOP, NIOS2_INSN_ORI, unsigned_immed16_overflow}, + {"rdctl", "d,c", "d,c,E", 2, + OP_MATCH_RDCTL, OP_MASK_RDCTL, 0, no_overflow}, + {"ret", "", "E", 0, + OP_MATCH_RET, OP_MASK, 0, no_overflow}, + {"rol", "d,s,t", "d,s,t,E", 3, + OP_MATCH_ROL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"roli", "d,s,j", "d,s,j,E", 3, + OP_MATCH_ROLI, OP_MASK_ROLI, 0, unsigned_immed5_overflow}, + {"ror", "d,s,t", "d,s,t,E", 3, + OP_MATCH_ROR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"sll", "d,s,t", "d,s,t,E", 3, + OP_MATCH_SLL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"slli", "d,s,j", "d,s,j,E", 3, + OP_MATCH_SLLI, OP_MASK_SLLI, 0, unsigned_immed5_overflow}, + {"sra", "d,s,t", "d,s,t,E", 3, + OP_MATCH_SRA, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"srai", "d,s,j", "d,s,j,E", 3, + OP_MATCH_SRAI, OP_MASK_SRAI, 0, unsigned_immed5_overflow}, + {"srl", "d,s,t", "d,s,t,E", 3, + OP_MATCH_SRL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"srli", "d,s,j", "d,s,j,E", 3, + OP_MATCH_SRLI, OP_MASK_SRLI, 0, unsigned_immed5_overflow}, + {"stb", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STB, OP_MASK_IOP, 0, address_offset_overflow}, + {"stbio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STBIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"stc", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STC, OP_MASK_IOP, 0, address_offset_overflow}, + {"sth", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STH, OP_MASK_IOP, 0, address_offset_overflow}, + {"sthio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STHIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"stw", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STW, OP_MASK_IOP, 0, address_offset_overflow}, + {"stwio", "t,i(s)", "t,i(s)E", 3, + OP_MATCH_STWIO, OP_MASK_IOP, 0, address_offset_overflow}, + {"sub", "d,s,t", "d,s,t,E", 3, + OP_MATCH_SUB, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"sync", "", "E", 0, + OP_MATCH_SYNC, OP_MASK_SYNC, 0, no_overflow}, + {"trap", "", "E", 0, + OP_MATCH_TRAP, OP_MASK_TRAP, 0, no_overflow}, + {"eret", "", "E", 0, + OP_MATCH_ERET, OP_MASK, 0, no_overflow}, + {"custom", "l,d,s,t", "l,d,s,t,E", 4, + OP_MATCH_CUSTOM, OP_MASK_ROP, 0, custom_opcode_overflow}, + {"wrctl", "c,s", "c,s,E", 2, + OP_MATCH_WRCTL, OP_MASK_WRCTL, 0, no_overflow}, + {"xor", "d,s,t", "d,s,t,E", 3, + OP_MATCH_XOR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow}, + {"xorhi", "t,s,u", "t,s,u,E", 3, + OP_MATCH_XORHI, OP_MASK_IOP, 0, unsigned_immed16_overflow}, + {"xori", "t,s,u", "t,s,u,E", 3, + OP_MATCH_XORI, OP_MASK_IOP, NIOS2_INSN_XORI, unsigned_immed16_overflow} +}; + +#define NIOS2_NUM_OPCODES \ + ((sizeof nios2_builtin_opcodes) / (sizeof (nios2_builtin_opcodes[0]))) +const int bfd_nios2_num_builtin_opcodes = NIOS2_NUM_OPCODES; + +/* This is not const to allow for dynamic extensions to the + built-in instruction set. */ +struct nios2_opcode *nios2_opcodes = + (struct nios2_opcode *) nios2_builtin_opcodes; +int bfd_nios2_num_opcodes = NIOS2_NUM_OPCODES; +#undef NIOS2_NUM_OPCODES |