From: Sandra Loosemore Date: Tue, 26 Nov 2024 19:13:07 +0000 (+0000) Subject: nios2: Remove binutils support for Nios II target. X-Git-Tag: gdb-16-branchpoint~291 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e7a16d9fd65098045ef5959bf98d990f12314111;p=thirdparty%2Fbinutils-gdb.git nios2: Remove binutils support for Nios II target. The Nios II architecture has been EOL'ed by the vendor. This patch removes all binutils, bfd, gas, binutils, and opcodes support for this target with the exception of the readelf utility. (The ELF EM_* number remains valid and the relocation definitions from the Nios II ABI will never change in future, so retaining the readelf support seems consistent with its purpose as a utility that tries to parse the headers in any ELF file provided as an argument regardless of target.) --- diff --git a/bfd/Makefile.am b/bfd/Makefile.am index 0dc733eaba9..dadbd0f7882 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -144,7 +144,6 @@ ALL_MACHINES = \ cpu-mt.lo \ cpu-nds32.lo \ cpu-nfp.lo \ - cpu-nios2.lo \ cpu-ns32k.lo \ cpu-or1k.lo \ cpu-pdp11.lo \ @@ -228,7 +227,6 @@ ALL_MACHINES_CFILES = \ cpu-mt.c \ cpu-nds32.c \ cpu-nfp.c \ - cpu-nios2.c \ cpu-ns32k.c \ cpu-or1k.c \ cpu-pdp11.c \ @@ -333,7 +331,6 @@ BFD32_BACKENDS = \ elf32-msp430.lo \ elf32-mt.lo \ elf32-nds32.lo \ - elf32-nios2.lo \ elf32-or1k.lo \ elf32-pj.lo \ elf32-ppc.lo \ @@ -468,7 +465,6 @@ BFD32_BACKENDS_CFILES = \ elf32-msp430.c \ elf32-mt.c \ elf32-nds32.c \ - elf32-nios2.c \ elf32-or1k.c \ elf32-pj.c \ elf32-ppc.c \ @@ -708,7 +704,7 @@ SOURCE_HFILES = \ ecoff-bfd.h ecoffswap.h \ elf32-arm.h elf32-avr.h elf32-bfin.h elf32-cr16.h elf32-csky.h \ elf32-dlx.h elf32-hppa.h elf32-m68hc1x.h elf32-m68k.h \ - elf32-metag.h elf32-nds32.h elf32-nios2.h elf32-ppc.h \ + elf32-metag.h elf32-nds32.h elf32-ppc.h \ elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \ elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \ elf64-hppa.h elf64-ppc.h elf64-tilegx.h \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index 38364f4b2ba..a781e2b8959 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -610,7 +610,6 @@ ALL_MACHINES = \ cpu-mt.lo \ cpu-nds32.lo \ cpu-nfp.lo \ - cpu-nios2.lo \ cpu-ns32k.lo \ cpu-or1k.lo \ cpu-pdp11.lo \ @@ -694,7 +693,6 @@ ALL_MACHINES_CFILES = \ cpu-mt.c \ cpu-nds32.c \ cpu-nfp.c \ - cpu-nios2.c \ cpu-ns32k.c \ cpu-or1k.c \ cpu-pdp11.c \ @@ -800,7 +798,6 @@ BFD32_BACKENDS = \ elf32-msp430.lo \ elf32-mt.lo \ elf32-nds32.lo \ - elf32-nios2.lo \ elf32-or1k.lo \ elf32-pj.lo \ elf32-ppc.lo \ @@ -935,7 +932,6 @@ BFD32_BACKENDS_CFILES = \ elf32-msp430.c \ elf32-mt.c \ elf32-nds32.c \ - elf32-nios2.c \ elf32-or1k.c \ elf32-pj.c \ elf32-ppc.c \ @@ -1172,7 +1168,7 @@ SOURCE_HFILES = \ ecoff-bfd.h ecoffswap.h \ elf32-arm.h elf32-avr.h elf32-bfin.h elf32-cr16.h elf32-csky.h \ elf32-dlx.h elf32-hppa.h elf32-m68hc1x.h elf32-m68k.h \ - elf32-metag.h elf32-nds32.h elf32-nios2.h elf32-ppc.h \ + elf32-metag.h elf32-nds32.h elf32-ppc.h \ elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \ elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \ elf64-hppa.h elf64-ppc.h elf64-tilegx.h \ @@ -1524,7 +1520,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nds32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nfp.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-or1k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-pdp11.Plo@am__quote@ @@ -1614,7 +1609,6 @@ distclean-compile: @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-nds32.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nios2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or1k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ppc.Plo@am__quote@ diff --git a/bfd/archures.c b/bfd/archures.c index c4decc59e4a..5c104af6ef3 100644 --- a/bfd/archures.c +++ b/bfd/archures.c @@ -536,10 +536,6 @@ DESCRIPTION .#define bfd_mach_aarch64_8R 1 .#define bfd_mach_aarch64_ilp32 32 .#define bfd_mach_aarch64_llp64 64 -. bfd_arch_nios2, {* Nios II. *} -.#define bfd_mach_nios2 0 -.#define bfd_mach_nios2r1 1 -.#define bfd_mach_nios2r2 2 . bfd_arch_visium, {* Visium. *} .#define bfd_mach_visium 1 . bfd_arch_wasm32, {* WebAssembly. *} @@ -681,7 +677,6 @@ 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_nds32_arch; extern const bfd_arch_info_type bfd_nfp_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_or1k_arch; extern const bfd_arch_info_type bfd_pdp11_arch; @@ -770,7 +765,6 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_mt_arch, &bfd_nds32_arch, &bfd_nfp_arch, - &bfd_nios2_arch, &bfd_ns32k_arch, &bfd_or1k_arch, &bfd_pdp11_arch, diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 3b047d922f3..092a6587c1c 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1802,10 +1802,6 @@ enum bfd_architecture #define bfd_mach_aarch64_8R 1 #define bfd_mach_aarch64_ilp32 32 #define bfd_mach_aarch64_llp64 64 - bfd_arch_nios2, /* Nios II. */ -#define bfd_mach_nios2 0 -#define bfd_mach_nios2r1 1 -#define bfd_mach_nios2r2 2 bfd_arch_visium, /* Visium. */ #define bfd_mach_visium 1 bfd_arch_wasm32, /* WebAssembly. */ @@ -6164,60 +6160,6 @@ enum bfd_reloc_code_real BFD_RELOC_MSP430_SET_ULEB128, BFD_RELOC_MSP430_SUB_ULEB128, - /* 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, - BFD_RELOC_NIOS2_CALL26_NOAT, - BFD_RELOC_NIOS2_GOT_LO, - BFD_RELOC_NIOS2_GOT_HA, - BFD_RELOC_NIOS2_CALL_LO, - BFD_RELOC_NIOS2_CALL_HA, - BFD_RELOC_NIOS2_R2_S12, - BFD_RELOC_NIOS2_R2_I10_1_PCREL, - BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, - BFD_RELOC_NIOS2_R2_T1I7_2, - BFD_RELOC_NIOS2_R2_T2I4, - BFD_RELOC_NIOS2_R2_T2I4_1, - BFD_RELOC_NIOS2_R2_T2I4_2, - BFD_RELOC_NIOS2_R2_X1I7_2, - BFD_RELOC_NIOS2_R2_X2L5, - BFD_RELOC_NIOS2_R2_F1I5_2, - BFD_RELOC_NIOS2_R2_L5I4X1, - BFD_RELOC_NIOS2_R2_T1X1I6, - BFD_RELOC_NIOS2_R2_T1X1I6_2, - /* PRU LDI 16-bit unsigned data-memory relocation. */ BFD_RELOC_PRU_U16, diff --git a/bfd/config.bfd b/bfd/config.bfd index 6553aac1e99..e2b09a2a92e 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -204,7 +204,6 @@ m68*) targ_archs=bfd_m68k_arch ;; microblaze*) targ_archs=bfd_microblaze_arch ;; mips*) targ_archs=bfd_mips_arch ;; nds32*) targ_archs=bfd_nds32_arch ;; -nios2*) targ_archs=bfd_nios2_arch ;; or1k*|or1knd*) targ_archs=bfd_or1k_arch ;; pdp11*) targ_archs=bfd_pdp11_arch ;; pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; @@ -1070,21 +1069,6 @@ case "${targ}" in targ_underscore=yes ;; - nios2eb-*-*) - targ_defvec=nios2_elf32_be_vec - targ_selvecs=nios2_elf32_le_vec - ;; - - nios2el-*-*) - targ_defvec=nios2_elf32_le_vec - targ_selvecs=nios2_elf32_be_vec - ;; - - nios2-*-*) - targ_defvec=nios2_elf32_le_vec - targ_selvecs=nios2_elf32_be_vec - ;; - or1k-*-elf | or1k-*-linux* | or1k-*-rtems*) targ_defvec=or1k_elf32_vec ;; diff --git a/bfd/configure b/bfd/configure index b50cb7571d8..2db9f76b9eb 100755 --- a/bfd/configure +++ b/bfd/configure @@ -15977,8 +15977,6 @@ do nds32_elf32_linux_be_vec) tb="$tb elf32-nds32.lo elf32.lo $elf" ;; nds32_elf32_linux_le_vec) tb="$tb elf32-nds32.lo elf32.lo $elf" ;; nfp_elf64_vec) tb="$tb elf64-nfp.lo elf64.lo $elf" ;; - nios2_elf32_be_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; - nios2_elf32_le_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; ns32k_aout_pc532mach_vec) tb="$tb pc532-mach.lo aout-ns32k.lo" ;; ns32k_aout_pc532nbsd_vec) tb="$tb ns32knetbsd.lo aout-ns32k.lo" ;; or1k_elf32_vec) tb="$tb elf32-or1k.lo elf32.lo $elf" ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index 6bcfd1b7368..465a7463d48 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -563,8 +563,6 @@ do nds32_elf32_linux_be_vec) tb="$tb elf32-nds32.lo elf32.lo $elf" ;; nds32_elf32_linux_le_vec) tb="$tb elf32-nds32.lo elf32.lo $elf" ;; nfp_elf64_vec) tb="$tb elf64-nfp.lo elf64.lo $elf" ;; - nios2_elf32_be_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; - nios2_elf32_le_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; ns32k_aout_pc532mach_vec) tb="$tb pc532-mach.lo aout-ns32k.lo" ;; ns32k_aout_pc532nbsd_vec) tb="$tb ns32knetbsd.lo aout-ns32k.lo" ;; or1k_elf32_vec) tb="$tb elf32-or1k.lo elf32.lo $elf" ;; diff --git a/bfd/cpu-nios2.c b/bfd/cpu-nios2.c deleted file mode 100644 index 4b81b3ec9f5..00000000000 --- a/bfd/cpu-nios2.c +++ /dev/null @@ -1,75 +0,0 @@ -/* BFD support for the Altera Nios II processor. - Copyright (C) 2012-2024 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" - -static const bfd_arch_info_type * -nios2_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - if (a->arch != b->arch) - return NULL; - - if (a->bits_per_word != b->bits_per_word) - return NULL; - - if (a->mach == bfd_mach_nios2) - return a; - else if (b->mach == bfd_mach_nios2) - return b; - else if (a->mach != b->mach) - return NULL; - - return a; -} - -#define N(NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - 32, /* Bits in a word. */ \ - 32, /* Bits in an address. */ \ - 8, /* Bits in a byte. */ \ - bfd_arch_nios2, \ - NUMBER, \ - "nios2", \ - PRINT, \ - 3, \ - DEFAULT, \ - nios2_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT, \ - 0 /* Maximum offset of a reloc from the start of an insn. */ \ - } - -#define NIOS2R1_NEXT &arch_info_struct[0] -#define NIOS2R2_NEXT &arch_info_struct[1] - -static const bfd_arch_info_type arch_info_struct[2] = -{ - N (bfd_mach_nios2r1, "nios2:r1", false, NIOS2R2_NEXT), - N (bfd_mach_nios2r2, "nios2:r2", false, NULL), -}; - -const bfd_arch_info_type bfd_nios2_arch = - N (bfd_mach_nios2, "nios2", true, NIOS2R1_NEXT); diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 96cf11936ae..b756e73736e 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -558,7 +558,6 @@ enum elf_target_id MIPS_ELF_DATA, MN10300_ELF_DATA, NDS32_ELF_DATA, - NIOS2_ELF_DATA, OR1K_ELF_DATA, PPC32_ELF_DATA, PPC64_ELF_DATA, diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index ebe162f2e5f..6e0da8c4dd8 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -2145,7 +2145,6 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, /* Fall thru */ case bfd_arch_frv: case bfd_arch_i386: - case bfd_arch_nios2: BFD_ASSERT (htab->hgot != NULL && ((htab->hgot->root.type == bfd_link_hash_defined) diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c deleted file mode 100644 index f6580af9519..00000000000 --- a/bfd/elf32-nios2.c +++ /dev/null @@ -1,6086 +0,0 @@ -/* 32-bit ELF support for Nios II. - Copyright (C) 2012-2024 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" -#include "elf32-nios2.h" -#include "libiberty.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 nios2_elf32_le_vec; -extern const bfd_target nios2_elf32_be_vec; - -/* Offset of tp and dtp pointers from start of TLS block. */ -#define TP_OFFSET 0x7000 -#define DTP_OFFSET 0x8000 - -/* The relocation tables used for SHT_REL sections. There are separate - tables for R1 and R2 encodings. */ -static reloc_howto_type elf_nios2_r1_howto_table_rel[] = { - /* No relocation. */ - HOWTO (R_NIOS2_NONE, /* type */ - 0, /* rightshift */ - 0, /* size */ - 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 */ - 4, /* size */ - 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 */ - 4, /* size */ - 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 */ - 4, /* size */ - 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 */ - 4, /* size */ - 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, - 4, - 5, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM5", - false, - 0x000007c0, - 0x000007c0, - false), - - HOWTO (R_NIOS2_CACHE_OPX, - 0, - 4, - 5, - false, - 22, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CACHE_OPX", - false, - 0x07c00000, - 0x07c00000, - false), - - HOWTO (R_NIOS2_IMM6, - 0, - 4, - 6, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM6", - false, - 0x00000fc0, - 0x00000fc0, - false), - - HOWTO (R_NIOS2_IMM8, - 0, - 4, - 8, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM8", - false, - 0x00003fc0, - 0x00003fc0, - false), - - HOWTO (R_NIOS2_HI16, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_hi16_relocate, - "R_NIOS2_HI16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_LO16, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_lo16_relocate, - "R_NIOS2_LO16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_HIADJ16, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_hiadj16_relocate, - "R_NIOS2_HIADJ16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_BFD_RELOC_32, - 0, - 4, /* 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, - 2, /* 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, - 1, /* byte */ - 8, - false, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC8", - false, - 0x000000ff, - 0x000000ff, - false), - - HOWTO (R_NIOS2_GPREL, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_gprel_relocate, - "R_NIOS2_GPREL", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_GNU_VTINHERIT, - 0, - 4, - 0, - false, - 0, - complain_overflow_dont, - NULL, - "R_NIOS2_GNU_VTINHERIT", - false, - 0, - 0, - false), - - HOWTO (R_NIOS2_GNU_VTENTRY, - 0, - 4, - 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, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_ujmp_relocate, - "R_NIOS2_UJMP", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_CJMP, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_cjmp_relocate, - "R_NIOS2_CJMP", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_CALLR, - 0, - 4, - 32, - false, - 6, - complain_overflow_dont, - nios2_elf32_callr_relocate, - "R_NIOS2_CALLR", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_ALIGN, - 0, - 4, - 0, - false, - 0, - complain_overflow_dont, - nios2_elf32_ignore_reloc, - "R_NIOS2_ALIGN", - false, - 0, - 0, - true), - - - HOWTO (R_NIOS2_GOT16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_GOT16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_CALL16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CALL16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_GOTOFF_LO, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_LO", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_GOTOFF_HA, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_HA", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_PCREL_LO, - 0, - 4, - 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, - 4, - 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, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_GD16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_TLS_LDM16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDM16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_TLS_LDO16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDO16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_TLS_IE16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_IE16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_TLS_LE16, - 0, - 4, - 16, - false, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LE16", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_TLS_DTPMOD, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPMOD", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_TLS_DTPREL, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPREL", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_TLS_TPREL, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_TPREL", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_COPY, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_COPY", - false, - 0, - 0, - false), - - HOWTO (R_NIOS2_GLOB_DAT, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GLOB_DAT", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_JUMP_SLOT, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_JUMP_SLOT", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_RELATIVE, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_RELATIVE", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_GOTOFF, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_CALL26_NOAT, /* type */ - 2, /* rightshift */ - 4, /* size */ - 26, /* bitsize */ - false, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26_NOAT", /* name */ - false, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - false), /* pcrel_offset */ - - HOWTO (R_NIOS2_GOT_LO, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_LO", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_GOT_HA, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_HA", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_CALL_LO, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_LO", - false, - 0x003fffc0, - 0x003fffc0, - false), - - HOWTO (R_NIOS2_CALL_HA, - 0, - 4, - 16, - false, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_HA", - false, - 0x003fffc0, - 0x003fffc0, - false), - -/* Add other relocations here. */ -}; - -static reloc_howto_type elf_nios2_r2_howto_table_rel[] = { - /* No relocation. */ - HOWTO (R_NIOS2_NONE, /* type */ - 0, /* rightshift */ - 0, /* size */ - 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 */ - 4, /* size */ - 16, /* bitsize */ - false, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_S16", /* name */ - false, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - false), /* pcrel_offset */ - - /* 16-bit unsigned immediate relocation. */ - HOWTO (R_NIOS2_U16, /* type */ - 0, /* rightshift */ - 4, /* size */ - 16, /* bitsize */ - false, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_unsigned, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_U16", /* name */ - false, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - false), /* pcrel_offset */ - - HOWTO (R_NIOS2_PCREL16, /* type */ - 0, /* rightshift */ - 4, /* size */ - 16, /* bitsize */ - true, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - nios2_elf32_pcrel16_relocate, /* special function */ - "R_NIOS2_PCREL16", /* name */ - false, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - true), /* pcrel_offset */ - - HOWTO (R_NIOS2_CALL26, /* type */ - 2, /* rightshift */ - 4, /* size */ - 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, - 4, - 5, - false, - 21, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM5", - false, - 0x03e00000, - 0x03e00000, - false), - - HOWTO (R_NIOS2_CACHE_OPX, - 0, - 4, - 5, - false, - 11, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CACHE_OPX", - false, - 0x0000f800, - 0x0000f800, - false), - - HOWTO (R_NIOS2_IMM6, - 0, - 4, - 6, - false, - 26, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM6", - false, - 0xfc000000, - 0xfc000000, - false), - - HOWTO (R_NIOS2_IMM8, - 0, - 4, - 8, - false, - 24, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM8", - false, - 0xff000000, - 0xff000000, - false), - - HOWTO (R_NIOS2_HI16, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_hi16_relocate, - "R_NIOS2_HI16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_LO16, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_lo16_relocate, - "R_NIOS2_LO16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_HIADJ16, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_hiadj16_relocate, - "R_NIOS2_HIADJ16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_BFD_RELOC_32, - 0, - 4, /* 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, - 2, /* 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, - 1, /* byte */ - 8, - false, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC8", - false, - 0x000000ff, - 0x000000ff, - false), - - HOWTO (R_NIOS2_GPREL, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_gprel_relocate, - "R_NIOS2_GPREL", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_GNU_VTINHERIT, - 0, - 4, - 0, - false, - 0, - complain_overflow_dont, - NULL, - "R_NIOS2_GNU_VTINHERIT", - false, - 0, - 0, - false), - - HOWTO (R_NIOS2_GNU_VTENTRY, - 0, - 4, - 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, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_ujmp_relocate, - "R_NIOS2_UJMP", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_CJMP, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_cjmp_relocate, - "R_NIOS2_CJMP", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_CALLR, - 0, - 4, - 32, - false, - 16, - complain_overflow_dont, - nios2_elf32_callr_relocate, - "R_NIOS2_CALLR", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_ALIGN, - 0, - 4, - 0, - false, - 0, - complain_overflow_dont, - nios2_elf32_ignore_reloc, - "R_NIOS2_ALIGN", - false, - 0, - 0, - true), - - HOWTO (R_NIOS2_GOT16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_GOT16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_CALL16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CALL16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_GOTOFF_LO, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_LO", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_GOTOFF_HA, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_HA", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_PCREL_LO, - 0, - 4, - 16, - true, - 16, - complain_overflow_dont, - nios2_elf32_pcrel_lo16_relocate, - "R_NIOS2_PCREL_LO", - false, - 0xffff0000, - 0xffff0000, - true), - - HOWTO (R_NIOS2_PCREL_HA, - 0, - 4, - 16, - false, /* This is a PC-relative relocation, but we need to subtract - PC ourselves before the HIADJ. */ - 16, - complain_overflow_dont, - nios2_elf32_pcrel_hiadj16_relocate, - "R_NIOS2_PCREL_HA", - false, - 0xffff0000, - 0xffff0000, - true), - - HOWTO (R_NIOS2_TLS_GD16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_GD16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_TLS_LDM16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDM16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_TLS_LDO16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDO16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_TLS_IE16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_IE16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_TLS_LE16, - 0, - 4, - 16, - false, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LE16", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_TLS_DTPMOD, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPMOD", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_TLS_DTPREL, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPREL", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_TLS_TPREL, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_TPREL", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_COPY, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_COPY", - false, - 0, - 0, - false), - - HOWTO (R_NIOS2_GLOB_DAT, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GLOB_DAT", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_JUMP_SLOT, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_JUMP_SLOT", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_RELATIVE, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_RELATIVE", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_GOTOFF, - 0, - 4, - 32, - false, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF", - false, - 0xffffffff, - 0xffffffff, - false), - - HOWTO (R_NIOS2_CALL26_NOAT, /* type */ - 2, /* rightshift */ - 4, /* size */ - 26, /* bitsize */ - false, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26_NOAT", /* name */ - false, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - false), /* pcrel_offset */ - - HOWTO (R_NIOS2_GOT_LO, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_LO", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_GOT_HA, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_HA", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_CALL_LO, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_LO", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_CALL_HA, - 0, - 4, - 16, - false, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_HA", - false, - 0xffff0000, - 0xffff0000, - false), - - HOWTO (R_NIOS2_R2_S12, - 0, - 4, - 12, - false, - 16, - complain_overflow_signed, - bfd_elf_generic_reloc, - "R_NIOS2_R2_S12", - false, - 0x0fff0000, - 0x0fff0000, - false), - - HOWTO (R_NIOS2_R2_I10_1_PCREL, - 1, - 2, - 10, - true, - 6, - complain_overflow_signed, - bfd_elf_generic_reloc, /* FIXME? */ - "R_NIOS2_R2_I10_1_PCREL", - false, - 0xffc0, - 0xffc0, - true), - - HOWTO (R_NIOS2_R2_T1I7_1_PCREL, - 1, - 2, - 7, - true, - 9, - complain_overflow_signed, - bfd_elf_generic_reloc, /* FIXME? */ - "R_NIOS2_R2_T1I7_1_PCREL", - false, - 0xfe00, - 0xfe00, - true), - - HOWTO (R_NIOS2_R2_T1I7_2, - 2, - 2, - 7, - false, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1I7_2", - false, - 0xfe00, - 0xfe00, - false), - - HOWTO (R_NIOS2_R2_T2I4, - 0, - 2, - 4, - false, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4", - false, - 0xf000, - 0xf000, - false), - - HOWTO (R_NIOS2_R2_T2I4_1, - 1, - 2, - 4, - false, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4_1", - false, - 0xf000, - 0xf000, - false), - - HOWTO (R_NIOS2_R2_T2I4_2, - 2, - 2, - 4, - false, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4_2", - false, - 0xf000, - 0xf000, - false), - - HOWTO (R_NIOS2_R2_X1I7_2, - 2, - 2, - 7, - false, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_X1I7_2", - false, - 0x1fc0, - 0x1fc0, - false), - - HOWTO (R_NIOS2_R2_X2L5, - 0, - 2, - 5, - false, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_X2L5", - false, - 0x07c0, - 0x07c0, - false), - - HOWTO (R_NIOS2_R2_F1I5_2, - 2, - 2, - 5, - false, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_F1L5_2", - false, - 0x07c0, - 0x07c0, - false), - - HOWTO (R_NIOS2_R2_L5I4X1, - 2, - 2, - 4, - false, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_L5I4X1", - false, - 0x03c0, - 0x03c0, - false), - - HOWTO (R_NIOS2_R2_T1X1I6, - 0, - 2, - 6, - false, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1X1I6", - false, - 0x7e00, - 0x7e00, - false), - - HOWTO (R_NIOS2_R2_T1X1I6_2, - 2, - 4, - 6, - false, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1I1X6_2", - false, - 0x7e00, - 0x7e00, - false), - -/* Add other relocations here. */ -}; - -static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; - - -/* Return true if producing output for a R2 BFD. */ -#define BFD_IS_R2(abfd) (bfd_get_mach (abfd) == bfd_mach_nios2r2) - -/* Return the howto for relocation RTYPE. */ -static reloc_howto_type * -lookup_howto (unsigned int rtype, bfd *abfd) -{ - static int initialized = 0; - int i; - /* R2 relocations are a superset of R1, so use that for the lookup - table. */ - int r1_howto_tbl_size = (int) ARRAY_SIZE (elf_nios2_r1_howto_table_rel); - int r2_howto_tbl_size = (int) ARRAY_SIZE (elf_nios2_r2_howto_table_rel); - - if (!initialized) - { - initialized = 1; - memset (elf_code_to_howto_index, 0xff, - sizeof (elf_code_to_howto_index)); - for (i = 0; i < r2_howto_tbl_size; i++) - { - elf_code_to_howto_index[elf_nios2_r2_howto_table_rel[i].type] = i; - if (i < r1_howto_tbl_size) - BFD_ASSERT (elf_nios2_r2_howto_table_rel[i].type - == elf_nios2_r1_howto_table_rel[i].type); - } - } - - if (rtype > R_NIOS2_ILLEGAL) - return NULL; - i = elf_code_to_howto_index[rtype]; - if (BFD_IS_R2 (abfd)) - { - if (i >= r2_howto_tbl_size) - return NULL; - return elf_nios2_r2_howto_table_rel + i; - } - else - { - if (i >= r1_howto_tbl_size) - return NULL; - return elf_nios2_r1_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_NONE, R_NIOS2_NONE}, - {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}, - {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT}, - {BFD_RELOC_NIOS2_GOT_LO, R_NIOS2_GOT_LO}, - {BFD_RELOC_NIOS2_GOT_HA, R_NIOS2_GOT_HA}, - {BFD_RELOC_NIOS2_CALL_LO, R_NIOS2_CALL_LO}, - {BFD_RELOC_NIOS2_CALL_HA, R_NIOS2_CALL_HA}, - {BFD_RELOC_NIOS2_R2_S12, R_NIOS2_R2_S12}, - {BFD_RELOC_NIOS2_R2_I10_1_PCREL, R_NIOS2_R2_I10_1_PCREL}, - {BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, R_NIOS2_R2_T1I7_1_PCREL}, - {BFD_RELOC_NIOS2_R2_T1I7_2, R_NIOS2_R2_T1I7_2}, - {BFD_RELOC_NIOS2_R2_T2I4, R_NIOS2_R2_T2I4}, - {BFD_RELOC_NIOS2_R2_T2I4_1, R_NIOS2_R2_T2I4_1}, - {BFD_RELOC_NIOS2_R2_T2I4_2, R_NIOS2_R2_T2I4_2}, - {BFD_RELOC_NIOS2_R2_X1I7_2, R_NIOS2_R2_X1I7_2}, - {BFD_RELOC_NIOS2_R2_X2L5, R_NIOS2_R2_X2L5}, - {BFD_RELOC_NIOS2_R2_F1I5_2, R_NIOS2_R2_F1I5_2}, - {BFD_RELOC_NIOS2_R2_L5I4X1, R_NIOS2_R2_L5I4X1}, - {BFD_RELOC_NIOS2_R2_T1X1I6, R_NIOS2_R2_T1X1I6}, - {BFD_RELOC_NIOS2_R2_T1X1I6_2, R_NIOS2_R2_T1X1I6_2}, -}; - -enum elf32_nios2_stub_type -{ - nios2_stub_call26_before, - nios2_stub_call26_after, - nios2_stub_none -}; - -struct elf32_nios2_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry bh_root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; - - enum elf32_nios2_stub_type stub_type; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf32_nios2_link_hash_entry *hh; - - /* And the reloc addend that this was derived from. */ - bfd_vma addend; - - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; -}; - -#define nios2_stub_hash_entry(ent) \ - ((struct elf32_nios2_stub_hash_entry *)(ent)) - -#define nios2_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_nios2_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - - -/* Nios II ELF linker hash entry. */ - -struct elf32_nios2_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct elf32_nios2_stub_hash_entry *hsh_cache; - -#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 - CALL_USED, meaning - (got_types_used & (GOT_USED | CALL_USED)) == CALL_USED. - */ -#define GOT_USED 1 -#define CALL_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; - - /* The stub hash table. */ - struct bfd_hash_table bstab; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *, bool); - void (*layout_sections_again) (void); - - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub - { - /* These are the section to which stubs in the group will be - attached. */ - asection *first_sec, *last_sec; - /* The stub sections. There might be stubs inserted either before - or after the real section.*/ - asection *first_stub_sec, *last_stub_sec; - } *stub_group; - - /* Assorted information used by nios2_elf32_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection **input_list; - Elf_Internal_Sym **all_local_syms; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sbss; - - /* GOT pointer symbol _gp_got. */ - struct elf_link_hash_entry *h_gp_got; - - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - 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. */ - bool 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 */ -}; - -/* CALL26 stub. */ -static const bfd_vma nios2_call26_stub_entry[] = { - 0x00400034, /* orhi at, r0, %hiadj(dest) */ - 0x08400004, /* addi at, at, %lo(dest) */ - 0x0800683a /* jmp at */ -}; - -/* 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_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; - } -} - -/* 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; -} - -/* Implement elf_backend_grok_prstatus: - Support for core dump NOTE sections. */ -static bool -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 bool -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; -} - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ -static struct bfd_hash_entry * -stub_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_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_nios2_stub_hash_entry *hsh; - - /* Initialize the local fields. */ - hsh = (struct elf32_nios2_stub_hash_entry *) entry; - hsh->stub_sec = NULL; - hsh->stub_offset = 0; - hsh->target_value = 0; - hsh->target_section = NULL; - hsh->stub_type = nios2_stub_none; - hsh->hh = NULL; - hsh->id_sec = NULL; - } - - return entry; -} - -/* 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->hsh_cache = NULL; - eh->tls_type = GOT_UNKNOWN; - eh->got_types_used = 0; - } - - return entry; -} - -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" - -/* Build a name for an entry in the stub hash table. */ -static char * -nios2_stub_name (const asection *input_section, - const asection *sym_sec, - const struct elf32_nios2_link_hash_entry *hh, - const Elf_Internal_Rela *rel, - enum elf32_nios2_stub_type stub_type) -{ - char *stub_name; - bfd_size_type len; - char stubpos = (stub_type == nios2_stub_call26_before) ? 'b' : 'a'; - - if (hh) - { - len = 8 + 1 + 1 + 1+ strlen (hh->root.root.root.string) + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%c_%s+%x", - input_section->id & 0xffffffff, - stubpos, - hh->root.root.root.string, - (int) rel->r_addend & 0xffffffff); - } - } - else - { - len = 8 + 1 + 1 + 1+ 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%c_%x:%x+%x", - input_section->id & 0xffffffff, - stubpos, - sym_sec->id & 0xffffffff, - (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff); - } - } - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ -static struct elf32_nios2_stub_hash_entry * -nios2_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct elf32_nios2_link_hash_entry *hh, - const Elf_Internal_Rela *rel, - struct elf32_nios2_link_hash_table *htab, - enum elf32_nios2_stub_type stub_type) -{ - struct elf32_nios2_stub_hash_entry *hsh; - const asection *id_sec; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first/last section in the group, - depending on the stub section placement relative to the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - if (stub_type == nios2_stub_call26_before) - id_sec = htab->stub_group[input_section->id].first_sec; - else - id_sec = htab->stub_group[input_section->id].last_sec; - - if (hh != NULL && hh->hsh_cache != NULL - && hh->hsh_cache->hh == hh - && hh->hsh_cache->id_sec == id_sec - && hh->hsh_cache->stub_type == stub_type) - { - hsh = hh->hsh_cache; - } - else - { - char *stub_name; - - stub_name = nios2_stub_name (id_sec, sym_sec, hh, rel, stub_type); - if (stub_name == NULL) - return NULL; - - hsh = nios2_stub_hash_lookup (&htab->bstab, - stub_name, false, false); - - if (hh != NULL) - hh->hsh_cache = hsh; - - free (stub_name); - } - - return hsh; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ -static struct elf32_nios2_stub_hash_entry * -nios2_add_stub (const char *stub_name, - asection *section, - struct elf32_nios2_link_hash_table *htab, - enum elf32_nios2_stub_type stub_type) -{ - asection *link_sec; - asection *stub_sec; - asection **secptr, **linkptr; - struct elf32_nios2_stub_hash_entry *hsh; - bool afterp; - - if (stub_type == nios2_stub_call26_before) - { - link_sec = htab->stub_group[section->id].first_sec; - secptr = &(htab->stub_group[section->id].first_stub_sec); - linkptr = &(htab->stub_group[link_sec->id].first_stub_sec); - afterp = false; - } - else - { - link_sec = htab->stub_group[section->id].last_sec; - secptr = &(htab->stub_group[section->id].last_stub_sec); - linkptr = &(htab->stub_group[link_sec->id].last_stub_sec); - afterp = true; - } - stub_sec = *secptr; - if (stub_sec == NULL) - { - stub_sec = *linkptr; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - - stub_sec = (*htab->add_stub_section) (s_name, link_sec, afterp); - if (stub_sec == NULL) - return NULL; - *linkptr = stub_sec; - } - *secptr = stub_sec; - } - - /* Enter this entry into the linker stub hash table. */ - hsh = nios2_stub_hash_lookup (&htab->bstab, stub_name, - true, false); - if (hsh == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%pB: cannot create stub entry %s"), - section->owner, - stub_name); - return NULL; - } - - hsh->stub_sec = stub_sec; - hsh->stub_offset = 0; - hsh->id_sec = link_sec; - return hsh; -} - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ -int -nios2_elf32_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - size_t amt; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - - htab->bfd_count = bfd_count; - - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); - if (htab->stub_group == NULL) - return -1; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - /* FIXME: This is a bit of hack. Currently our .ctors and .dtors - * have PC relative relocs in them but no code flag set. */ - if (((section->flags & SEC_CODE) != 0) || - strcmp(".ctors", section->name) || - strcmp(".dtors", section->name)) - input_list[section->index] = NULL; - } - - return 1; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ -void -nios2_elf32_next_input_section (struct bfd_link_info *info, asection *isec) -{ - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - if (isec->output_section->index <= htab->top_index) - { - asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) - { - /* Steal the last_sec pointer for our list. - This happens to make the list in reverse order, - which is what we want. */ - htab->stub_group[isec->id].last_sec = *list; - *list = isec; - } - } -} - -/* Segment mask for CALL26 relocation relaxation. */ -#define CALL26_SEGMENT(x) ((x) & 0xf0000000) - -/* Fudge factor for approximate maximum size of all stubs that might - be inserted by the linker. This does not actually limit the number - of stubs that might be inserted, and only affects strategy for grouping - and placement of stubs. Perhaps this should be computed based on number - of relocations seen, or be specifiable on the command line. */ -#define MAX_STUB_SECTION_SIZE 0xffff - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the end of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. - Rather than computing groups of a maximum fixed size, for Nios II - CALL26 relaxation it makes more sense to compute the groups based on - sections that fit within a 256MB address segment. Also do not allow - a group to span more than one output section, since different output - sections might correspond to different memory banks on a bare-metal - target, etc. */ -static void -group_sections (struct elf32_nios2_link_hash_table *htab) -{ - asection **list = htab->input_list + htab->top_index; - do - { - /* The list is in reverse order so we'll search backwards looking - for the first section that begins in the same memory segment, - marking sections along the way to point at the tail for this - group. */ - asection *tail = *list; - if (tail == bfd_abs_section_ptr) - continue; - while (tail != NULL) - { - bfd_vma start = tail->output_section->vma + tail->output_offset; - bfd_vma end = start + tail->size; - bfd_vma segment = CALL26_SEGMENT (end); - asection *prev; - - if (segment != CALL26_SEGMENT (start) - || segment != CALL26_SEGMENT (end + MAX_STUB_SECTION_SIZE)) - /* This section spans more than one memory segment, or is - close enough to the end of the segment that adding stub - sections before it might cause it to move so that it - spans memory segments, or that stubs added at the end of - this group might overflow into the next memory segment. - Put it in a group by itself to localize the effects. */ - { - prev = htab->stub_group[tail->id].last_sec; - htab->stub_group[tail->id].last_sec = tail; - htab->stub_group[tail->id].first_sec = tail; - } - else - /* Collect more sections for this group. */ - { - asection *curr, *first; - for (curr = tail; ; curr = prev) - { - prev = htab->stub_group[curr->id].last_sec; - if (!prev - || tail->output_section != prev->output_section - || (CALL26_SEGMENT (prev->output_section->vma - + prev->output_offset) - != segment)) - break; - } - first = curr; - for (curr = tail; ; curr = prev) - { - prev = htab->stub_group[curr->id].last_sec; - htab->stub_group[curr->id].last_sec = tail; - htab->stub_group[curr->id].first_sec = first; - if (curr == first) - break; - } - } - - /* Reset tail for the next group. */ - tail = prev; - } - } - while (list-- != htab->input_list); - free (htab->input_list); -} - -/* Determine the type of stub needed, if any, for a call. */ -static enum elf32_nios2_stub_type -nios2_type_of_stub (asection *input_sec, - const Elf_Internal_Rela *rel, - struct elf32_nios2_link_hash_entry *hh, - struct elf32_nios2_link_hash_table *htab, - bfd_vma destination, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - bfd_vma location, segment, start, end; - asection *s0, *s1, *s; - - if (hh != NULL && - !(hh->root.root.type == bfd_link_hash_defined - || hh->root.root.type == bfd_link_hash_defweak)) - return nios2_stub_none; - - /* Determine where the call point is. */ - location = (input_sec->output_section->vma - + input_sec->output_offset + rel->r_offset); - segment = CALL26_SEGMENT (location); - - /* Nios II CALL and JMPI instructions can transfer control to addresses - within the same 256MB segment as the PC. */ - if (segment == CALL26_SEGMENT (destination)) - return nios2_stub_none; - - /* Find the start and end addresses of the stub group. Also account for - any already-created stub sections for this group. Note that for stubs - in the end section, only the first instruction of the last stub - (12 bytes long) needs to be within range. */ - s0 = htab->stub_group[input_sec->id].first_sec; - s = htab->stub_group[s0->id].first_stub_sec; - if (s != NULL && s->size > 0) - start = s->output_section->vma + s->output_offset; - else - start = s0->output_section->vma + s0->output_offset; - - s1 = htab->stub_group[input_sec->id].last_sec; - s = htab->stub_group[s1->id].last_stub_sec; - if (s != NULL && s->size > 0) - end = s->output_section->vma + s->output_offset + s->size - 8; - else - end = s1->output_section->vma + s1->output_offset + s1->size; - - BFD_ASSERT (start < end); - BFD_ASSERT (start <= location); - BFD_ASSERT (location < end); - - /* Put stubs at the end of the group unless that is not a valid - location and the beginning of the group is. It might be that - neither the beginning nor end works if we have an input section - so large that it spans multiple segment boundaries. In that - case, punt; the end result will be a relocation overflow error no - matter what we do here. - - Note that adding stubs pushes up the addresses of all subsequent - sections, so that stubs allocated on one pass through the - relaxation loop may not be valid on the next pass. (E.g., we may - allocate a stub at the beginning of the section on one pass and - find that the call site has been bumped into the next memory - segment on the next pass.) The important thing to note is that - we never try to reclaim the space allocated to such unused stubs, - so code size and section addresses can only increase with each - iteration. Accounting for the start and end addresses of the - already-created stub sections ensures that when the algorithm - converges, it converges accurately, with the entire appropriate - stub section accessible from the call site and not just the - address at the start or end of the stub group proper. */ - - if (segment == CALL26_SEGMENT (end)) - return nios2_stub_call26_after; - else if (segment == CALL26_SEGMENT (start)) - return nios2_stub_call26_before; - else - /* Perhaps this should be a dedicated error code. */ - return nios2_stub_none; -} - -static bool -nios2_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_nios2_stub_hash_entry *hsh - = (struct elf32_nios2_stub_hash_entry *) gen_entry; - asection *stub_sec = hsh->stub_sec; - bfd_vma sym_value; - struct bfd_link_info *info; - - info = (struct bfd_link_info *) in_arg; - - /* Fail if the target section could not be assigned to an output - section. The user should fix his linker script. */ - if (hsh->target_section->output_section == NULL - && info->non_contiguous_regions) - info->callbacks->einfo (_("%F%P: Could not assign `%pA' to an output section. " - "Retry without --enable-non-contiguous-regions.\n"), - hsh->target_section); - - /* Make a note of the offset within the stubs for this entry. */ - hsh->stub_offset = stub_sec->size; - - switch (hsh->stub_type) - { - case nios2_stub_call26_before: - case nios2_stub_call26_after: - /* A call26 stub looks like: - orhi at, %hiadj(dest) - addi at, at, %lo(dest) - jmp at - Note that call/jmpi instructions can't be used in PIC code - so there is no reason for the stub to be PIC, either. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma - + hsh->addend); - - nios2_elf32_install_data (stub_sec, nios2_call26_stub_entry, - hsh->stub_offset, 3); - nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset, - hiadj (sym_value)); - nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset + 4, - sym_value); - stub_sec->size += 12; - break; - default: - BFD_FAIL (); - return false; - } - - return true; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ -static bool -nios2_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_nios2_stub_hash_entry *hsh - = (struct elf32_nios2_stub_hash_entry *) gen_entry; - - switch (hsh->stub_type) - { - case nios2_stub_call26_before: - case nios2_stub_call26_after: - hsh->stub_sec->size += 12; - break; - default: - BFD_FAIL (); - return false; - } - return true; -} - -/* Read in all local syms for all input bfds. - Returns -1 on error, 0 otherwise. */ - -static int -get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd, - struct bfd_link_info *info) -{ - unsigned int bfd_indx; - Elf_Internal_Sym *local_syms, **all_local_syms; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - size_t amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; - all_local_syms = bfd_zmalloc (amt); - htab->all_local_syms = all_local_syms; - if (all_local_syms == NULL) - return -1; - - /* Walk over all the input BFDs, swapping in local symbols. */ - for (bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - return -1; - - all_local_syms[bfd_indx] = local_syms; - } - - return 0; -} - -/* Determine and set the size of the stub section for a final link. */ -bool -nios2_elf32_size_stubs (bfd *output_bfd, bfd *stub_bfd, - struct bfd_link_info *info, - asection *(*add_stub_section) (const char *, - asection *, bool), - void (*layout_sections_again) (void)) -{ - bool stub_changed = false; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; - - /* FIXME: We only compute the section groups once. This could cause - problems if adding a large stub section causes following sections, - or parts of them, to move into another segment. However, this seems - to be consistent with the way other back ends handle this.... */ - group_sections (htab); - - if (get_local_syms (output_bfd, info->input_bfds, info)) - { - if (htab->all_local_syms) - goto error_ret_free_local; - return false; - } - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - asection *stub_sec; - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = htab->all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - enum elf32_nios2_stub_type stub_type; - struct elf32_nios2_stub_hash_entry *hsh; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf32_nios2_link_hash_entry *hh; - char *stub_name; - const asection *id_sec; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= (unsigned int) R_NIOS2_ILLEGAL) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - - /* Only look for stubs on CALL and JMPI instructions. */ - if (r_type != (unsigned int) R_NIOS2_CALL26) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - hh = NULL; - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; - unsigned int shndx; - - sym = local_syms + r_indx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - shndx = sym->st_shndx; - if (shndx < elf_numsections (input_bfd)) - { - hdr = elf_elfsections (input_bfd)[shndx]; - sym_sec = hdr->bfd_section; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hh = ((struct elf32_nios2_link_hash_entry *) - elf_sym_hashes (input_bfd)[e_indx]); - - while (hh->root.root.type == bfd_link_hash_indirect - || hh->root.root.type == bfd_link_hash_warning) - hh = ((struct elf32_nios2_link_hash_entry *) - hh->root.root.u.i.link); - - if (hh->root.root.type == bfd_link_hash_defined - || hh->root.root.type == bfd_link_hash_defweak) - { - sym_sec = hh->root.root.u.def.section; - sym_value = hh->root.root.u.def.value; - - if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - else - continue; - } - else if (hh->root.root.type == bfd_link_hash_undefweak) - { - if (! bfd_link_pic (info)) - continue; - } - else if (hh->root.root.type == bfd_link_hash_undefined) - { - if (! (info->unresolved_syms_in_objects == RM_IGNORE - && (ELF_ST_VISIBILITY (hh->root.other) - == STV_DEFAULT))) - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - } - - /* Determine what (if any) linker stub is needed. */ - stub_type = nios2_type_of_stub (section, irela, hh, htab, - destination, info); - if (stub_type == nios2_stub_none) - continue; - - /* Support for grouping stub sections. */ - if (stub_type == nios2_stub_call26_before) - id_sec = htab->stub_group[section->id].first_sec; - else - id_sec = htab->stub_group[section->id].last_sec; - - /* Get the name of this stub. */ - stub_name = nios2_stub_name (id_sec, sym_sec, hh, irela, - stub_type); - if (!stub_name) - goto error_ret_free_internal; - - hsh = nios2_stub_hash_lookup (&htab->bstab, - stub_name, - false, false); - if (hsh != NULL) - { - /* The proper stub has already been created. */ - free (stub_name); - continue; - } - - hsh = nios2_add_stub (stub_name, section, htab, stub_type); - if (hsh == NULL) - { - free (stub_name); - goto error_ret_free_internal; - } - hsh->target_value = sym_value; - hsh->target_section = sym_sec; - hsh->stub_type = stub_type; - hsh->hh = hh; - hsh->addend = irela->r_addend; - stub_changed = true; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - if (!stub_changed) - break; - - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - stub_sec->size = 0; - - bfd_hash_traverse (&htab->bstab, nios2_size_one_stub, htab); - - /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); - stub_changed = false; - } - - free (htab->all_local_syms); - return true; - - error_ret_free_local: - free (htab->all_local_syms); - return false; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. This function is called via nios2elf_finish in the linker. */ -bool -nios2_elf32_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - /* The stub_bfd may contain non-stub sections if it is also the - dynobj. Any such non-stub sections are created with the - SEC_LINKER_CREATED flag set, while stub sections do not - have that flag. Ignore any non-stub sections here. */ - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - { - bfd_size_type size; - - /* Allocate memory to hold the linker stubs. */ - size = stub_sec->size; - stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return false; - stub_sec->size = 0; - } - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->bstab; - bfd_hash_traverse (table, nios2_build_one_stub, info); - - return true; -} - - -#define is_nios2_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_object_id (bfd) == NIOS2_ELF_DATA) - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bool -nios2_elf32_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - - if (!is_nios2_elf (ibfd) || !is_nios2_elf (obfd)) - return true; - - /* Check if we have the same endianness. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return false; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = true; - elf_elfheader (obfd)->e_flags = new_flags; - - switch (new_flags) - { - default: - case EF_NIOS2_ARCH_R1: - bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r1); - break; - case EF_NIOS2_ARCH_R2: - if (bfd_big_endian (ibfd)) - { - _bfd_error_handler - (_("error: %pB: big-endian R2 is not supported"), ibfd); - bfd_set_error (bfd_error_bad_value); - return false; - } - bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r2); - break; - } - } - - /* Incompatible flags. */ - else if (new_flags != old_flags) - { - /* So far, the only incompatible flags denote incompatible - architectures. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %pB: conflicting CPU architectures %d/%d"), - ibfd, new_flags, old_flags); - bfd_set_error (bfd_error_bad_value); - return false; - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, info); - - return true; -} - -/* 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, - bfd_reloc_code_real_type code) -{ - int i; - - for (i = 0; i < (int) ARRAY_SIZE (nios2_reloc_map); ++i) - if (nios2_reloc_map[i].bfd_val == code) - return lookup_howto (nios2_reloc_map[i].elf_val, abfd); - 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, - const char *r_name) -{ - int i; - reloc_howto_type *howto_tbl; - int howto_tbl_size; - - if (BFD_IS_R2 (abfd)) - { - howto_tbl = elf_nios2_r2_howto_table_rel; - howto_tbl_size = (int) ARRAY_SIZE (elf_nios2_r2_howto_table_rel); - } - else - { - howto_tbl = elf_nios2_r1_howto_table_rel; - howto_tbl_size = (int) ARRAY_SIZE (elf_nios2_r1_howto_table_rel); - } - - for (i = 0; i < howto_tbl_size; i++) - if (howto_tbl[i].name && strcasecmp (howto_tbl[i].name, r_name) == 0) - return howto_tbl + i; - - return NULL; -} - -/* Implement elf_info_to_howto: - Given a ELF32 relocation, fill in a arelent structure. */ - -static bool -nios2_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if ((cache_ptr->howto = lookup_howto (r_type, abfd)) == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%pB: unsupported relocation type %#x"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - return false; - } - return true; -} - -/* 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 bool -nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) -{ - - bool 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; - { - asection *sym_sec = lh->u.def.section; - bfd_vma sym_value = lh->u.def.value; - - if (sym_sec->output_section) - sym_value = (sym_value + sym_sec->output_offset - + sym_sec->output_section->vma); - *pgp = sym_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, bool 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; -} - -/* 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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 (CALL26_SEGMENT (symbol_value + addend) - != CALL26_SEGMENT (input_section->output_section->vma - + input_section->output_offset - + offset)) - return bfd_reloc_overflow; - - /* Check that the target address is correctly aligned on a 4-byte - boundary. */ - if ((symbol_value + addend) & 0x3) - 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, - 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, - 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, - 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, - 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 int -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; - bfd_vma got_base; - - 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); - - if (htab->h_gp_got == NULL) - got_base = 0; - else - got_base = htab->h_gp_got->root.u.def.value; - - 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_reloc_status_type r = bfd_reloc_ok; - const char *name = NULL; - int r_type; - const char *format; - char *msg = NULL; - bool 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), output_bfd); - 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 - { - bool warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - 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 (bfd_link_relocatable (info)) - continue; - - if (howto) - { - bool resolved_to_zero; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - 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)) - { - bfd_vma reloc_address; - - if (sec && sec->output_section) - reloc_address = (sec->output_section->vma - + sec->output_offset - + rel->r_offset); - else - reloc_address = 0; - - format = _("global pointer relative relocation at address " - "%#" PRIx64 " when _gp not defined\n"); - msg = bfd_asprintf (format, (uint64_t) reloc_address); - r = bfd_reloc_dangerous; - } - else - { - bfd_vma symbol_address = rel->r_addend + relocation; - relocation = symbol_address - 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)) - { - if (h) - 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 (sec); - } - /* xgettext:c-format */ - format = _("unable to reach %s (at %#" PRIx64 ") from " - "the global pointer (at %#" PRIx64 ") " - "because the offset (%" PRId64 ") is out of " - "the allowed range, -32678 to 32767\n" ); - msg = bfd_asprintf (format, name, - (uint64_t) symbol_address, - (uint64_t) gp, - (int64_t) relocation); - 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: - case R_NIOS2_CALL26_NOAT: - /* 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; - } - /* Detect R_NIOS2_CALL26 relocations that would overflow the - 256MB segment. Replace the target with a reference to a - trampoline instead. - Note that htab->stub_group is null if relaxation has been - disabled by the --no-relax linker command-line option, so - we can use that to skip this processing entirely. */ - if (howto->type == R_NIOS2_CALL26 && htab->stub_group) - { - bfd_vma dest = relocation + rel->r_addend; - enum elf32_nios2_stub_type stub_type; - - eh = (struct elf32_nios2_link_hash_entry *)h; - stub_type = nios2_type_of_stub (input_section, rel, eh, - htab, dest, NULL); - - if (stub_type != nios2_stub_none) - { - struct elf32_nios2_stub_hash_entry *hsh; - - hsh = nios2_get_stub_entry (input_section, sec, - eh, rel, htab, stub_type); - if (hsh == NULL) - { - r = bfd_reloc_undefined; - break; - } - - dest = (hsh->stub_offset - + hsh->stub_sec->output_offset - + hsh->stub_sec->output_section->vma); - r = nios2_elf32_do_call26_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - dest, 0); - break; - } - } - - /* Normal case. */ - 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: - case R_NIOS2_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - /* 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) - { - bool dyn; - - eh = (struct elf32_nios2_link_hash_entry *)h; - use_plt = (eh->got_types_used == CALL_USED - && h->plt.offset != (bfd_vma) -1); - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - || ((ELF_ST_VISIBILITY (h->other) - || resolved_to_zero) - && 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 (bfd_link_pic (info)) - { - 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 && bfd_link_pic (info)) - { - off = ((h->plt.offset - 24) / 12 + 3) * 4; - relocation = (htab->root.sgotplt->output_offset + off - - got_base); - } - else - relocation = sgot->output_offset + off - got_base; - - /* This relocation does not use the addend. */ - rel->r_addend = 0; - - switch (howto->type) - { - case R_NIOS2_GOT_LO: - case R_NIOS2_CALL_LO: - r = nios2_elf32_do_lo16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL_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_GOTOFF_LO: - case R_NIOS2_GOTOFF_HA: - case R_NIOS2_GOTOFF: - /* Relocation is relative to the global offset table pointer. */ - - 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. */ - relocation -= sgot->output_section->vma; - - /* Now we adjust the relocation to be relative to the GOT pointer - (the _gp_got symbol), which possibly contains the 0x8000 bias. */ - relocation -= got_base; - - 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 (bfd_link_pic (info)) - { - 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 - got_base; - - 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) - { - bool dyn; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !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 - { - bool 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 ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || 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 - got_base; - - 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 (bfd_link_dll (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB(%pA+%#" PRIx64 "): %s relocation not " - "permitted in shared object"), - input_bfd, input_section, - (uint64_t) 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 (bfd_link_pic (info) - && (input_section->flags & SEC_ALLOC) != 0 - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bool 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 - && (!bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !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 (sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) (info, NULL, name, - howto->name, (bfd_vma) 0, - input_bfd, input_section, - rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) (info, name, input_bfd, - input_section, - rel->r_offset, true); - break; - - case bfd_reloc_outofrange: - 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) - { - (*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 bool -nios2_elf32_section_flags (const Elf_Internal_Shdr *hdr) -{ - if (hdr->sh_flags & SHF_NIOS2_GPREL) - hdr->bfd_section->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 bool -nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, asection *sec) -{ - const char *name = bfd_section_name (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 bool -create_got_section (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf32_nios2_link_hash_table *htab; - struct elf_link_hash_entry *h; - - 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 (htab->root.sgotplt, 4)) - return false; - - /* The Nios II ABI specifies that GOT-relative relocations are relative - to the linker-created symbol _gp_got, rather than using - _GLOBAL_OFFSET_TABLE_ directly. In particular, the latter always - points to the base of the GOT while _gp_got may include a bias. */ - h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.sgotplt, - "_gp_got"); - htab->h_gp_got = h; - if (h == NULL) - 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 bool -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; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return false; - - /* 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. */ - return bfd_set_section_alignment (htab->root.splt, 4); -} - -/* 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 (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); -} - -/* Set the right machine number for a NIOS2 ELF file. */ - -static bool -nios2_elf32_object_p (bfd *abfd) -{ - unsigned long mach; - - mach = elf_elfheader (abfd)->e_flags; - - switch (mach) - { - default: - case EF_NIOS2_ARCH_R1: - bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r1); - break; - case EF_NIOS2_ARCH_R2: - bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r2); - break; - } - - return true; -} - -/* Implement elf_backend_check_relocs: - Look through the relocs for a section during the first phase. */ -static bool -nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf32_nios2_link_hash_table *htab; - asection *sreloc = NULL; - bfd_signed_vma *local_got_refcounts; - - if (bfd_link_relocatable (info)) - return true; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - htab = elf32_nios2_hash_table (info); - - 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_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL16: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - 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_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL16: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - 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 (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 - || r_type == R_NIOS2_CALL_LO - || r_type == R_NIOS2_CALL_HA) - { - /* 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 |= CALL_USED; - } - else - eh->got_types_used |= GOT_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; - } - } - make_got: - 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; - - case R_NIOS2_TLS_LDM16: - htab->tls_ldm_got.refcount++; - goto make_got; - - /* 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_CALL26_NOAT: - 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 (!bfd_link_pic (info)) - 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 || r_type == R_NIOS2_CALL26_NOAT) - h->needs_plt = 1; - } - - /* If we are creating a shared library, we need to copy the - reloc into the shared library. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (r_type == R_NIOS2_BFD_RELOC_32 - || (h != NULL && ! h->needs_plt - && (! SYMBOLIC_BIND (info, h) || ! h->def_regular)))) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->root.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 = &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->root.sym_cache, - abfd, r_symndx); - if (isym == NULL) - return false; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - size_t amt = sizeof *p; - p = ((struct elf_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, - 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_finish_dynamic_symbols: - Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ -static bool -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 (bfd_link_pic (info)) - { - bfd_vma br_offset; - - 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); - br_offset = -(h->plt.offset + 12); - /* If this plt entry is too far away from the start of .plt - for the "br" to reach .PLTresolve, bounce through one or - more of the previous "br" instructions. */ - if (br_offset < (bfd_vma) -32768) - { - br_offset += 32768 / 12 * 12 - 4; - while (br_offset < (bfd_vma) -32768) - br_offset += 32768 / 12 * 12; - } - nios2_elf32_install_imm16 (splt, h->plt.offset + 8, br_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); - - /* 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 == CALL_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 (bfd_link_pic (info) && 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)); - - 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; - if (h->root.u.def.section == htab->root.sdynrelro) - s = htab->root.sreldynrelro; - else - s = htab->root.srelbss; - BFD_ASSERT (s != NULL); - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark _DYNAMIC, _GLOBAL_OFFSET_TABLE_, and _gp_got as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || h == htab->root.hgot - || h == htab->h_gp_got) - sym->st_shndx = SHN_ABS; - - return true; -} - -/* Implement elf_backend_finish_dynamic_sections. */ -static bool -nios2_elf32_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *sgotplt; - asection *sdyn; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - sgotplt = htab->root.sgotplt; - sdyn = NULL; - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = htab->root.splt; - sdyn = bfd_get_linker_section (htab->root.dynobj, ".dynamic"); - BFD_ASSERT (splt != NULL && sdyn != NULL && sgotplt != 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 (htab->root.dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = htab->root.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_NIOS2_GP: - s = htab->root.sgotplt; - dyn.d_un.d_ptr - = s->output_section->vma + s->output_offset + 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 (bfd_link_pic (info)) - { - bfd_vma got_pcrel = got_address - (splt->output_section->vma - + splt->output_offset); - /* Both GOT and PLT must be aligned to a 16-byte boundary - for the two loads to share the %hiadj part. The 4-byte - offset for nextpc is accounted for in the %lo offsets - on the loads. */ - BFD_ASSERT ((got_pcrel & 0xf) == 0); - nios2_elf32_install_data (splt, nios2_so_plt0_entry, 0, 6); - nios2_elf32_install_imm16 (splt, 4, hiadj (got_pcrel)); - nios2_elf32_install_imm16 (splt, 12, got_pcrel); - nios2_elf32_install_imm16 (splt, 16, got_pcrel + 4); - } - 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); - - /* The GOT must be aligned to a 16-byte boundary for the - two loads to share the same %hiadj part. */ - BFD_ASSERT ((got_address & 0xf) == 0); - - 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); - nios2_elf32_install_imm16 (splt, res_size + 12, - hiadj (got_address)); - nios2_elf32_install_imm16 (splt, res_size + 16, - got_address + 4); - nios2_elf32_install_imm16 (splt, res_size + 20, - got_address + 8); - } - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgotplt != NULL && 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); - - if (sgotplt->output_section != bfd_abs_section_ptr) - 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 bool -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, *srel; - unsigned align2; - - htab = elf32_nios2_hash_table (info); - dynobj = htab->root.dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return true; - } - - /* 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 (bfd_link_pic (info)) - 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. */ - /* 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_READONLY) != 0) - { - s = htab->root.sdynrelro; - srel = htab->root.sreldynrelro; - } - else - { - s = htab->root.sdynbss; - srel = htab->root.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - 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_section_alignment (s) - && !bfd_set_section_alignment (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_late_size_sections. */ -static bool -adjust_dynrelocs (struct elf_link_hash_entry *h, void *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_late_size_sections. - Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ -static bool -allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct elf32_nios2_link_hash_table *htab; - struct elf32_nios2_link_hash_entry *eh; - struct elf_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, bfd_link_pic (info), h)) - { - asection *s = htab->root.splt; - - /* Allocate room for the header. */ - if (s->size == 0) - { - if (bfd_link_pic (info)) - 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 (! bfd_link_pic (info) - && !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 == CALL_USED - && h->plt.offset != (bfd_vma) -1); - - if (h->got.refcount > 0) - { - asection *s; - bool 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, bfd_link_pic (info), h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - indx = h->dynindx; - - if (tls_type != GOT_NORMAL - && (bfd_link_pic (info) || 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 - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (h->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 (bfd_link_pic (info)) - { - if (h->def_regular - && (h->forced_local || SYMBOLIC_BIND (info, h))) - { - struct elf_dyn_relocs **pp; - - for (pp = &h->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 (h->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) - { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - h->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; - } - - h->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = h->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_late_size_sections: - Set the sizes of the dynamic sections. */ -static bool -nios2_elf32_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bool relocs; - bfd *ibfd; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - dynobj = htab->root.dynobj; - if (dynobj == NULL) - return true; - - htab->res_n_size = 0; - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - 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 elf_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); - } - } - } - - 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 (bfd_link_pic (info) || *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 (bfd_link_pic (info)) - 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); - - if (htab->root.dynamic_sections_created) - { - /* If the .got section is more than 0x8000 bytes, we add - 0x8000 to the value of _gp_got, so that 16-bit relocations - have a greater chance of working. */ - if (htab->root.sgot->size >= 0x8000 - && htab->h_gp_got->root.u.def.value == 0) - htab->h_gp_got->root.u.def.value = 0x8000; - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - 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_section_name (s); - - if (startswith (name, ".rela")) - { - if (s->size != 0) - { - if (s != htab->root.srelplt) - 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 (s == htab->root.splt) - { - /* Correct for the number of res_N branches. */ - if (s->size != 0 && !bfd_link_pic (info)) - { - htab->res_n_size = (s->size - 28) / 3; - s->size += htab->res_n_size; - } - } - else if (s != htab->sbss - && s != htab->root.sgot - && s != htab->root.sgotplt - && s != htab->root.sdynbss - && s != htab->root.sdynrelro) - /* It's not one of our sections, so don't allocate space. */ - continue; - - if (s->size == 0) - { - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. */ - 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); - - return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs); -} - -/* Free the derived linker hash table. */ -static void -nios2_elf32_link_hash_table_free (bfd *obfd) -{ - struct elf32_nios2_link_hash_table *htab - = (struct elf32_nios2_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (&htab->bstab); - _bfd_elf_link_hash_table_free (obfd); -} - -/* 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; - size_t amt = sizeof (struct elf32_nios2_link_hash_table); - - ret = bfd_zmalloc (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; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&ret->bstab, stub_hash_newfunc, - sizeof (struct elf32_nios2_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = nios2_elf32_link_hash_table_free; - - return &ret->root.root; -} - -/* Implement elf_backend_reloc_type_class. */ -static enum elf_reloc_type_class -nios2_elf32_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_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 bool -is_nios2_elf_target (const struct bfd_target *targ) -{ - return (targ == &nios2_elf32_le_vec - || targ == &nios2_elf32_be_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 bool -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) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && 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_SMALL_DATA | SEC_LINKER_CREATED; - - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - - htab->sbss = bfd_make_section_anyway_with_flags (htab->root.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 bool -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 - -#define bfd_elf32_bfd_merge_private_bfd_data \ - nios2_elf32_merge_private_bfd_data - -/* 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_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 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_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_late_size_sections nios2_elf32_late_size_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_object_p nios2_elf32_object_p - -#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 nios2_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlenios2" -#define TARGET_BIG_SYM nios2_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bignios2" - -#define elf_backend_got_header_size 12 -#define elf_backend_default_execstack 0 - -#include "elf32-target.h" diff --git a/bfd/elf32-nios2.h b/bfd/elf32-nios2.h deleted file mode 100644 index 2f5e484b569..00000000000 --- a/bfd/elf32-nios2.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Nios II support for 32-bit ELF - Copyright (C) 2013-2024 Free Software Foundation, Inc. - Contributed by Mentor Graphics - - 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. */ - -#ifndef _ELF32_NIOS2_H -#define _ELF32_NIOS2_H - -extern int nios2_elf32_setup_section_lists - (bfd *, struct bfd_link_info *); - -extern void nios2_elf32_next_input_section - (struct bfd_link_info *, asection *); - -extern bool nios2_elf32_size_stubs - (bfd *, bfd *, struct bfd_link_info *, - asection * (*) (const char *, asection *, bool), void (*) (void)); - -extern bool nios2_elf32_build_stubs - (struct bfd_link_info *); - -#endif /* _ELF32_NIOS2_H */ diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 5da7541e06e..7d7ae1eaec9 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2895,58 +2895,6 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MSP430_SYM_DIFF", "BFD_RELOC_MSP430_SET_ULEB128", "BFD_RELOC_MSP430_SUB_ULEB128", - "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_NIOS2_CALL26_NOAT", - "BFD_RELOC_NIOS2_GOT_LO", - "BFD_RELOC_NIOS2_GOT_HA", - "BFD_RELOC_NIOS2_CALL_LO", - "BFD_RELOC_NIOS2_CALL_HA", - "BFD_RELOC_NIOS2_R2_S12", - "BFD_RELOC_NIOS2_R2_I10_1_PCREL", - "BFD_RELOC_NIOS2_R2_T1I7_1_PCREL", - "BFD_RELOC_NIOS2_R2_T1I7_2", - "BFD_RELOC_NIOS2_R2_T2I4", - "BFD_RELOC_NIOS2_R2_T2I4_1", - "BFD_RELOC_NIOS2_R2_T2I4_2", - "BFD_RELOC_NIOS2_R2_X1I7_2", - "BFD_RELOC_NIOS2_R2_X2L5", - "BFD_RELOC_NIOS2_R2_F1I5_2", - "BFD_RELOC_NIOS2_R2_L5I4X1", - "BFD_RELOC_NIOS2_R2_T1X1I6", - "BFD_RELOC_NIOS2_R2_T1X1I6_2", "BFD_RELOC_PRU_U16", "BFD_RELOC_PRU_U16_PMEMIMM", "BFD_RELOC_PRU_LDI32", diff --git a/bfd/reloc.c b/bfd/reloc.c index a187afe9b56..f60776299c8 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -6186,113 +6186,6 @@ ENUMX 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 -ENUMX - BFD_RELOC_NIOS2_CALL26_NOAT -ENUMX - BFD_RELOC_NIOS2_GOT_LO -ENUMX - BFD_RELOC_NIOS2_GOT_HA -ENUMX - BFD_RELOC_NIOS2_CALL_LO -ENUMX - BFD_RELOC_NIOS2_CALL_HA -ENUMX - BFD_RELOC_NIOS2_R2_S12 -ENUMX - BFD_RELOC_NIOS2_R2_I10_1_PCREL -ENUMX - BFD_RELOC_NIOS2_R2_T1I7_1_PCREL -ENUMX - BFD_RELOC_NIOS2_R2_T1I7_2 -ENUMX - BFD_RELOC_NIOS2_R2_T2I4 -ENUMX - BFD_RELOC_NIOS2_R2_T2I4_1 -ENUMX - BFD_RELOC_NIOS2_R2_T2I4_2 -ENUMX - BFD_RELOC_NIOS2_R2_X1I7_2 -ENUMX - BFD_RELOC_NIOS2_R2_X2L5 -ENUMX - BFD_RELOC_NIOS2_R2_F1I5_2 -ENUMX - BFD_RELOC_NIOS2_R2_L5I4X1 -ENUMX - BFD_RELOC_NIOS2_R2_T1X1I6 -ENUMX - BFD_RELOC_NIOS2_R2_T1X1I6_2 -ENUMDOC - Relocations used by the Altera Nios II core. - ENUM BFD_RELOC_PRU_U16 ENUMDOC diff --git a/bfd/targets.c b/bfd/targets.c index 0d5d73ba462..178e9d30a2b 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -833,8 +833,6 @@ extern const bfd_target nds32_elf32_le_vec; extern const bfd_target nds32_elf32_linux_be_vec; extern const bfd_target nds32_elf32_linux_le_vec; extern const bfd_target nfp_elf64_vec; -extern const bfd_target nios2_elf32_be_vec; -extern const bfd_target nios2_elf32_le_vec; extern const bfd_target ns32k_aout_pc532mach_vec; extern const bfd_target ns32k_aout_pc532nbsd_vec; extern const bfd_target or1k_elf32_vec; @@ -1217,9 +1215,6 @@ static const bfd_target * const _bfd_target_vector[] = &nfp_elf64_vec, #endif - &nios2_elf32_be_vec, - &nios2_elf32_le_vec, - &ns32k_aout_pc532mach_vec, &ns32k_aout_pc532nbsd_vec, diff --git a/binutils/MAINTAINERS b/binutils/MAINTAINERS index 6a584b5492d..fa991e3700d 100644 --- a/binutils/MAINTAINERS +++ b/binutils/MAINTAINERS @@ -117,8 +117,6 @@ responsibility among the other maintainers. Moxie Anthony Green NDS32 Kuan-Lin Chen NDS32 Wei-Cheng Wang - Nios II Sandra Loosemore - Nios II Andrew Jenner OR1K Christian Svensson OR1K Stefan Kristiansson OR1K Stafford Horne diff --git a/binutils/NEWS b/binutils/NEWS index 92cc9506c80..6da2258befe 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* Support for Nios II targets has been removed except in the readelf utility, + as this architecture has been EOL'ed by Intel. + * RISC-V disassembly now supports -M,max option like QEMU to dump instruction without checking architecture support as usual. diff --git a/configure b/configure index d6b4ea5094a..bbfb5979546 100755 --- a/configure +++ b/configure @@ -10742,9 +10742,6 @@ case "${target}" in mips*-*-*linux* | mips*-*-gnu*) target_makefile_frag="config/mt-mips-gnu" ;; - nios2-*-elf*) - target_makefile_frag="config/mt-nios2-elf" - ;; *-*-linux-android*) target_makefile_frag="config/mt-android" ;; diff --git a/configure.ac b/configure.ac index b31f0eaf6aa..f9694cdf901 100644 --- a/configure.ac +++ b/configure.ac @@ -2979,9 +2979,6 @@ case "${target}" in mips*-*-*linux* | mips*-*-gnu*) target_makefile_frag="config/mt-mips-gnu" ;; - nios2-*-elf*) - target_makefile_frag="config/mt-nios2-elf" - ;; *-*-linux-android*) target_makefile_frag="config/mt-android" ;; diff --git a/gas/Makefile.am b/gas/Makefile.am index d025b759875..54bc43ae6ff 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -186,7 +186,6 @@ TARGET_CPU_CFILES = \ config/tc-msp430.c \ config/tc-mt.c \ config/tc-nds32.c \ - config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-or1k.c \ config/tc-pdp11.c \ @@ -260,7 +259,6 @@ TARGET_CPU_HFILES = \ config/tc-msp430.h \ config/tc-mt.h \ config/tc-nds32.h \ - config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-or1k.h \ config/tc-pdp11.h \ diff --git a/gas/Makefile.in b/gas/Makefile.in index fde7aa7d2c3..68db33d58bc 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -685,7 +685,6 @@ TARGET_CPU_CFILES = \ config/tc-msp430.c \ config/tc-mt.c \ config/tc-nds32.c \ - config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-or1k.c \ config/tc-pdp11.c \ @@ -759,7 +758,6 @@ TARGET_CPU_HFILES = \ config/tc-msp430.h \ config/tc-mt.h \ config/tc-nds32.h \ - config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-or1k.h \ config/tc-pdp11.h \ @@ -993,7 +991,6 @@ CPU_DOCS = \ doc/c-mmix.texi \ doc/c-mt.texi \ doc/c-msp430.texi \ - doc/c-nios2.texi \ doc/c-nds32.texi \ doc/c-ns32k.texi \ doc/c-or1k.texi \ @@ -1187,8 +1184,6 @@ config/tc-mt.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) config/tc-nds32.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) -config/tc-nios2.$(OBJEXT): config/$(am__dirstamp) \ - config/$(DEPDIR)/$(am__dirstamp) config/tc-ns32k.$(OBJEXT): config/$(am__dirstamp) \ config/$(DEPDIR)/$(am__dirstamp) config/tc-or1k.$(OBJEXT): config/$(am__dirstamp) \ @@ -1419,7 +1414,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-msp430.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-mt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-nds32.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-nios2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-ns32k.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-or1k.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@config/$(DEPDIR)/tc-pdp11.Po@am__quote@ diff --git a/gas/NEWS b/gas/NEWS index d4143da39c4..23eda334ec6 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* Support for Nios II targets has been dropped, as the architecture has + been EOL'ed by Intel. + * Add support for the x86 Intel MSR_IMM instructions. * Add support for the x86 Zhaoxin GMI instructions. diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index 7d6d1737446..96394a5edf9 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -57,10 +57,6 @@ #include "elf/mep.h" #endif -#ifdef TC_NIOS2 -#include "elf/nios2.h" -#endif - #ifdef TC_PRU #include "elf/pru.h" #endif diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c deleted file mode 100644 index bd96629fe91..00000000000 --- a/gas/config/tc-nios2.c +++ /dev/null @@ -1,4103 +0,0 @@ -/* Altera Nios II assembler. - Copyright (C) 2012-2024 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"; - -const 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}, -#define OPTION_MARCH (OPTION_MD_BASE + 5) - {"march", required_argument, NULL, OPTION_MARCH} -}; - -const 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. */ -static 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. */ - bool noat; - - /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without - warning. - .set break -> nobreak = 0, assembly code using ba,bt warns. */ - bool 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; - - /* Constant bits masked into insn_code for self-check mode. */ - unsigned long constant_bits; - - /* 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 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 htab_t nios2_opcode_hash = NULL; -#define nios2_opcode_lookup(NAME) \ - ((struct nios2_opcode *) str_hash_find (nios2_opcode_hash, (NAME))) - -/* Register hash table. */ -static htab_t nios2_reg_hash = NULL; -#define nios2_reg_lookup(NAME) \ - ((struct nios2_reg *) str_hash_find (nios2_reg_hash, (NAME))) - - -/* Pseudo-op hash table. */ -static htab_t nios2_ps_hash = NULL; -#define nios2_ps_lookup(NAME) \ - ((nios2_ps_insn_infoS *) str_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 preceding instructions. */ -static symbolS *nios2_last_label; - -/* If we saw a 16-bit CDX instruction, we can align on 2-byte boundaries - instead of 4-bytes. Use this to keep track of the minimum power-of-2 - alignment. */ -static int nios2_min_align = 2; - -#ifdef OBJ_ELF -/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ -symbolS *GOT_symbol; -#endif - -/* The processor architecture value, EF_NIOS2_ARCH_R1 by default. */ -static int nios2_architecture = EF_NIOS2_ARCH_R1; - - -/** 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 | ((valueT) (buf[i] & 0xff) << 8 * (n - (i + 1))); - else - for (i = 0; i < n; ++i) - val = val | ((valueT) (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. */ -const 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 is prefixed with a special relocation operator. */ -static int -nios2_special_relocation_p (const char *str) -{ - return (startswith (str, "%lo") - || startswith (str, "%hi") - || startswith (str, "%hiadj") - || startswith (str, "%gprel") - || startswith (str, "%got") - || startswith (str, "%call") - || startswith (str, "%gotoff_lo") - || startswith (str, "%gotoff_hiadj") - || startswith (str, "%tls_gd") - || startswith (str, "%tls_ldm") - || startswith (str, "%tls_ldo") - || startswith (str, "%tls_ie") - || startswith (str, "%tls_le") - || startswith (str, "%gotoff")); -} - - -/* nop fill patterns for text section. */ -static char const nop_r1[4] = { 0x3a, 0x88, 0x01, 0x00 }; -static char const nop_r2[4] = { 0x20, 0x00, 0x00, 0xc4 }; -static char const nop_r2_cdx[2] = { 0x3b, 0x00 }; -static char const *nop32 = nop_r1; -static char const *nop16 = NULL; - -/* 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 >= nios2_min_align) - { - /* First, make sure we're on the minimum boundary, in case - someone has been putting .byte values the text section. */ - if (nios2_current_align < nios2_min_align || switched_seg_p) - frag_align (nios2_min_align, 0, 0); - - /* If we might be on a 2-byte boundary, first align to a - 4-byte boundary using the 2-byte nop as fill. */ - if (nios2_min_align == 1 - && align > nios2_min_align - && pfill == nop32 ) - { - gas_assert (nop16); - frag_align_pattern (2, nop16, 2, 0); - } - - /* Now fill in the alignment pattern. */ - if (pfill != NULL) - frag_align_pattern (align, pfill, 4, 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 *) nop32; - 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) -{ - obj_elf_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) -{ - obj_elf_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 *save = input_line_pointer; - char *directive; - char delim = get_symbol_name (&directive); - char *endline = input_line_pointer; - - (void) restore_line_pointer (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]) - { - bool 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 = save; - 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. - - 16-bit CDX branch instructions are relaxed first into equivalent - 32-bit branches and then the above transformations are applied - if necessary. - -*/ - -/* 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 and a bit for 16-bit CDX instructions. - 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 CDXBRANCH (1 << 17) -#define IS_CBRANCH(SUBTYPE) ((SUBTYPE) & CBRANCH) -#define IS_UBRANCH(SUBTYPE) (!IS_CBRANCH (SUBTYPE)) -#define IS_CDXBRANCH(SUBTYPE) ((SUBTYPE) & CDXBRANCH) -#define UBRANCH_SUBTYPE(N) (UBRANCH | (N)) -#define CBRANCH_SUBTYPE(N) (CBRANCH | (N)) -#define CDX_UBRANCH_SUBTYPE(N) (CDXBRANCH | UBRANCH | (N)) -#define CDX_CBRANCH_SUBTYPE(N) (CDXBRANCH | CBRANCH | (N)) -#define SUBTYPE_ADDIS(SUBTYPE) ((SUBTYPE) & 0xffff) - -/* For the -relax-section mode, unconditional branches require 2 extra - instructions 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 (IS_CDXBRANCH (subtype) ? 2 : 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; - bool is_cdx = false; - - 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 fr_var (4 for 32-bit insns) because all pc relative - branches are from the next instruction. */ - offset = target - fragp->fr_address - fragp->fr_fix - fragp->fr_var; - if (IS_CDXBRANCH (subtype) && IS_UBRANCH (subtype) - && offset >= -1024 && offset < 1024) - /* PC-relative CDX branch with 11-bit offset. */ - is_cdx = true; - else if (IS_CDXBRANCH (subtype) && IS_CBRANCH (subtype) - && offset >= -128 && offset < 128) - /* PC-relative CDX branch with 8-bit offset. */ - is_cdx = true; - else if (offset >= -32768 && offset < 32768) - /* 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_cdx) - fragp->fr_subtype = subtype; - else 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, op; - offsetT addend, remainder; - int i; - bool is_r2 = (bfd_get_mach (stdoutput) == bfd_mach_nios2r2); - - /* If this is a CDX branch we're not relaxing, just generate the fixup. */ - if (IS_CDXBRANCH (subtype)) - { - gas_assert (is_r2); - fix_new (fragp, fragp->fr_fix, 2, fragp->fr_symbol, - fragp->fr_offset, 1, - (IS_UBRANCH (subtype) - ? BFD_RELOC_NIOS2_R2_I10_1_PCREL - : BFD_RELOC_NIOS2_R2_T1I7_1_PCREL)); - fragp->fr_fix += 2; - return; - } - - /* If this is a CDX branch we are relaxing, turn it into an equivalent - 32-bit branch and then fall through to the normal non-CDX cases. */ - if (fragp->fr_var == 2) - { - unsigned int opcode = md_chars_to_number (buffer, 2); - gas_assert (is_r2); - if (IS_CBRANCH (subtype)) - { - unsigned int reg = nios2_r2_reg3_mappings[GET_IW_T1I7_A3 (opcode)]; - if (GET_IW_R2_OP (opcode) == R2_OP_BNEZ_N) - opcode = MATCH_R2_BNE | SET_IW_F2I16_A (reg); - else - opcode = MATCH_R2_BEQ | SET_IW_F2I16_A (reg); - } - else - opcode = MATCH_R2_BR; - md_number_to_chars (buffer, opcode, 4); - fragp->fr_var = 4; - } - - /* 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; - unsigned int old_op, new_op; - 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); - if (is_r2) - { - old_op = GET_IW_R2_OP (br_opcode); - switch (old_op) - { - case R2_OP_BEQ: - new_op = R2_OP_BNE; - break; - case R2_OP_BNE: - new_op = R2_OP_BEQ; - break; - case R2_OP_BGE: - new_op = R2_OP_BLT; - break; - case R2_OP_BGEU: - new_op = R2_OP_BLTU; - break; - case R2_OP_BLT: - new_op = R2_OP_BGE; - break; - case R2_OP_BLTU: - new_op = R2_OP_BGEU; - break; - default: - abort (); - } - br_opcode = ((br_opcode & ~IW_R2_OP_SHIFTED_MASK) - | SET_IW_R2_OP (new_op)); - br_opcode = br_opcode | SET_IW_F2I16_IMM16 (nbytes); - } - else - { - old_op = GET_IW_R1_OP (br_opcode); - switch (old_op) - { - case R1_OP_BEQ: - new_op = R1_OP_BNE; - break; - case R1_OP_BNE: - new_op = R1_OP_BEQ; - break; - case R1_OP_BGE: - new_op = R1_OP_BLT; - break; - case R1_OP_BGEU: - new_op = R1_OP_BLTU; - break; - case R1_OP_BLT: - new_op = R1_OP_BGE; - break; - case R1_OP_BLTU: - new_op = R1_OP_BGEU; - break; - default: - abort (); - } - br_opcode = ((br_opcode & ~IW_R1_OP_SHIFTED_MASK) - | SET_IW_R1_OP (new_op)); - br_opcode = br_opcode | SET_IW_I_IMM16 (nbytes); - } - 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. */ - if (is_r2) - op = MATCH_R2_NEXTPC | SET_IW_F3X6L5_C (AT_REGNUM); - else - op = MATCH_R1_NEXTPC | SET_IW_R_C (AT_REGNUM); - md_number_to_chars (buffer, op, 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; - if (is_r2) - addend_mask = SET_IW_F2I16_IMM16 ((unsigned int)addend); - else - addend_mask = SET_IW_I_IMM16 ((unsigned int)addend); - - /* Insert n-1 addi instructions. */ - if (is_r2) - addi_mask = (MATCH_R2_ADDI - | SET_IW_F2I16_B (AT_REGNUM) - | SET_IW_F2I16_A (AT_REGNUM)); - else - addi_mask = (MATCH_R1_ADDI - | SET_IW_I_B (AT_REGNUM) - | SET_IW_I_A (AT_REGNUM)); - 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); - if (is_r2) - addend_mask = SET_IW_F2I16_IMM16 ((unsigned int)remainder); - else - addend_mask = SET_IW_I_IMM16 ((unsigned int)remainder); - md_number_to_chars (buffer, addi_mask | addend_mask, 4); - fragp->fr_fix += 4; - buffer += 4; - } - - /* Load at for the absolute case. */ - else - { - if (is_r2) - op = MATCH_R2_ORHI | SET_IW_F2I16_B (AT_REGNUM) | SET_IW_F2I16_A (0); - else - op = MATCH_R1_ORHI | SET_IW_I_B (AT_REGNUM) | SET_IW_I_A (0); - md_number_to_chars (buffer, op, 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; - if (is_r2) - op = (MATCH_R2_ORI | SET_IW_F2I16_B (AT_REGNUM) - | SET_IW_F2I16_A (AT_REGNUM)); - else - op = (MATCH_R1_ORI | SET_IW_I_B (AT_REGNUM) - | SET_IW_I_A (AT_REGNUM)); - md_number_to_chars (buffer, op, 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. */ - if (is_r2) - op = MATCH_R2_JMP | SET_IW_F3X6L5_A (AT_REGNUM); - else - op = MATCH_R1_JMP | SET_IW_R_A (AT_REGNUM); - md_number_to_chars (buffer, op, 4); - fragp->fr_fix += 4; - buffer += 4; -} - - -/** Fixups and overflow checking. */ - -/* Check a fixup for overflow. */ -static bool -nios2_check_overflow (valueT fixup, reloc_howto_type *howto) -{ - /* If there is a rightshift, check that the low-order bits are - zero before applying it. */ - if (howto->rightshift) - { - if ((~(~((valueT) 0) << howto->rightshift) & fixup) - && howto->complain_on_overflow != complain_overflow_dont) - return true; - 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) (~0U << (howto->bitsize - 1))) - 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; - - opcode = nios2_find_opcode_hash (value, bfd_get_mach (stdoutput)); - gas_assert (opcode); - gas_assert (fixP->fx_size == opcode->size); - 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: - if (opcode->format == iw_i_type || opcode->format == iw_F2I16_type) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("branch offset %d out of range %d to %d"), - (int)fixup, -32768, 32767); - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("branch offset %d out of range"), - (int)fixup); - break; - case address_offset_overflow: - if (opcode->format == iw_i_type || opcode->format == iw_F2I16_type) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("%s offset %d out of range %d to %d"), - opcode->name, (int)fixup, -32768, 32767); - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("%s offset %d out of range"), - opcode->name, (int)fixup); - 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 signed_immed12_overflow: - as_bad_where (fixP->fx_file, fixP->fx_line, - _("immediate value %d out of range %d to %d"), - (int)fixup, -2048, 2047); - 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 - || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT - || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_LO - || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_HA - || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_LO - || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_HA - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_S12 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_I10_1_PCREL - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1I7_1_PCREL - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1I7_2 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4_1 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4_2 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_X1I7_2 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_X2L5 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_F1I5_2 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_L5I4X1 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1X1I6 - || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1X1I6_2 - /* 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 - + fixP->fx_size)); - *valP = fixup; - } - - /* 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 = (offsetT) 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 + 0x8000) >> 16) & 0xFFFF; - break; - default: - { - fixup &= ((valueT) 2 << (howto->bitsize - 1)) - 1; - 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. */ - -/* General internal error routine. */ - -static void -bad_opcode (const struct nios2_opcode *op) -{ - fprintf (stderr, _("internal error: broken opcode descriptor for `%s %s'\n"), - op->name, op->args); - as_fatal (_("Broken assembler. No assembly attempted.")); -} - -/* Special relocation directive strings. */ - -struct nios2_special_relocS -{ - const char *string; - bfd_reloc_code_real_type reloc_type; -}; - -/* This table is sorted so that prefix strings are listed after the longer - strings that include them -- e.g., %got after %got_hiadj, etc. */ - -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_lo", BFD_RELOC_NIOS2_CALL_LO}, - {"%call_hiadj", BFD_RELOC_NIOS2_CALL_HA}, - {"%call", BFD_RELOC_NIOS2_CALL16}, - {"%gotoff_lo", BFD_RELOC_NIOS2_GOTOFF_LO}, - {"%gotoff_hiadj", BFD_RELOC_NIOS2_GOTOFF_HA}, - {"%gotoff", BFD_RELOC_NIOS2_GOTOFF}, - {"%got_hiadj", BFD_RELOC_NIOS2_GOT_HA}, - {"%got_lo", BFD_RELOC_NIOS2_GOT_LO}, - {"%got", BFD_RELOC_NIOS2_GOT16}, - {"%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}, -}; - -#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 = XNEW (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 - -/* Look up a register name and validate it for the given regtype. - Return the register mapping or NULL on failure. */ -static struct nios2_reg * -nios2_parse_reg (const char *token, unsigned long regtype) -{ - struct nios2_reg *reg = nios2_reg_lookup (token); - - if (reg == NULL) - { - as_bad (_("unknown register %s"), token); - return NULL; - } - - /* Matched a register, but is it the wrong type? */ - if (!(regtype & reg->regtype)) - { - if (regtype & REG_CONTROL) - as_bad (_("expecting control register")); - else if (reg->regtype & REG_CONTROL) - as_bad (_("illegal use of control register")); - else if (reg->regtype & REG_COPROCESSOR) - as_bad (_("illegal use of coprocessor register")); - else - as_bad (_("invalid register %s"), token); - return NULL; - } - - /* Warn for explicit use of special registers. */ - if (reg->regtype & REG_NORMAL) - { - if (!nios2_as_options.noat && reg->index == 1) - as_warn (_("Register at (r1) can sometimes be corrupted by " - "assembler optimizations.\n" - "Use .set noat to turn off those optimizations " - "(and this warning).")); - if (!nios2_as_options.nobreak && reg->index == 25) - as_warn (_("The debugger will corrupt bt (r25).\n" - "If you don't need to debug this " - "code use .set nobreak to turn off this warning.")); - if (!nios2_as_options.nobreak && reg->index == 30) - as_warn (_("The debugger will corrupt sstatus/ba (r30).\n" - "If you don't need to debug this " - "code use .set nobreak to turn off this warning.")); - } - - return reg; -} - -/* This function parses a reglist for ldwm/stwm and push.n/pop.n - instructions, given as a brace-enclosed register list. The tokenizer - has replaced commas in the token with spaces. - The return value is a bitmask of registers in the set. It also - sets nios2_reglist_mask and nios2_reglist_dir to allow error checking - when parsing the base register. */ - -static unsigned long nios2_reglist_mask; -static int nios2_reglist_dir; - -static unsigned long -nios2_parse_reglist (char *token, const struct nios2_opcode *op) -{ - unsigned long mask = 0; - int dir = 0; - unsigned long regtype = 0; - int last = -1; - const char *regname; - - nios2_reglist_mask = 0; - nios2_reglist_dir = 0; - - if (op->match == MATCH_R2_LDWM || op->match == MATCH_R2_STWM) - { - regtype = REG_LDWM; - dir = 0; - } - else if (op->match == MATCH_R2_PUSH_N) - { - regtype = REG_POP; - dir = -1; - } - else if (op->match == MATCH_R2_POP_N) - { - regtype = REG_POP; - dir = 1; - } - else - bad_opcode (op); - - for (regname = strtok (token, "{ }"); - regname; - regname = strtok (NULL, "{ }")) - { - int regno; - struct nios2_reg *reg = nios2_parse_reg (regname, regtype); - - if (!reg) - break; - regno = reg->index; - - /* Make sure registers are listed in proper sequence. */ - if (last >= 0) - { - if (regno == last) - { - as_bad ("duplicate register %s\n", reg->name); - return 0; - } - else if (dir == 0) - dir = (regno < last ? -1 : 1); - else if ((dir > 0 && regno < last) - || (dir < 0 && regno > last) - || (op->match == MATCH_R2_PUSH_N - && ! ((last == 31 && regno == 28) - || (last == 31 && regno <= 23) - || (last == 28 && regno <= 23) - || (regno < 23 && regno == last - 1))) - || (op->match == MATCH_R2_POP_N - && ! ((regno == 31 && last == 28) - || (regno == 31 && last <= 23) - || (regno == 28 && last <= 23) - || (last < 23 && last == regno - 1)))) - { - as_bad ("invalid register order"); - return 0; - } - } - - mask |= 1UL << regno; - last = regno; - } - - /* Check that all ldwm/stwm regs belong to the same set. */ - if ((op->match == MATCH_R2_LDWM || op->match == MATCH_R2_STWM) - && (mask & 0x00003ffc) && (mask & 0x90ffc000)) - { - as_bad ("invalid register set in reglist"); - return 0; - } - - /* Check that push.n/pop.n regs include RA. */ - if ((op->match == MATCH_R2_PUSH_N || op->match == MATCH_R2_POP_N) - && ((mask & 0x80000000) == 0)) - { - as_bad ("reglist must include ra (r31)"); - return 0; - } - - /* Check that there is at least one register in the set. */ - if (!mask) - { - as_bad ("reglist must include at least one register"); - return 0; - } - - /* OK, reglist passed validation. */ - nios2_reglist_mask = mask; - nios2_reglist_dir = dir; - return mask; -} - -/* This function parses the base register and options used by the ldwm/stwm - instructions. Returns the base register and sets the option arguments - accordingly. On failure, returns NULL. */ -static struct nios2_reg * -nios2_parse_base_register (char *str, int *direction, int *writeback, int *ret) -{ - char *regname; - struct nios2_reg *reg; - - *direction = 0; - *writeback = 0; - *ret = 0; - - /* Check for --. */ - if (startswith (str, "--")) - { - str += 2; - *direction -= 1; - } - - /* Extract the base register. */ - if (*str != '(') - { - as_bad ("expected '(' before base register"); - return NULL; - } - str++; - regname = str; - str = strchr (str, ')'); - if (!str) - { - as_bad ("expected ')' after base register"); - return NULL; - } - *str = '\0'; - str++; - reg = nios2_parse_reg (regname, REG_NORMAL); - if (reg == NULL) - return NULL; - - /* Check for ++. */ - if (startswith (str, "++")) - { - str += 2; - *direction += 1; - } - - /* Ensure that either -- or ++ is specified, but not both. */ - if (*direction == 0) - { - as_bad ("invalid base register syntax"); - return NULL;; - } - - /* Check for options. The tokenizer has replaced commas with spaces. */ - while (*str) - { - while (*str == ' ') - str++; - if (startswith (str, "writeback")) - { - *writeback = 1; - str += 9; - } - else if (startswith (str, "ret")) - { - *ret = 1; - str += 3; - } - else if (*str) - { - as_bad ("invalid option syntax"); - return NULL; - } - } - - return reg; -} - - -/* 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, - bfd_reloc_code_real_type orig_reloc_type, - unsigned int pcrel) -{ - nios2_insn_relocS *reloc; - char *saved_line_ptr; - unsigned long value = 0; - int i; - bfd_reloc_code_real_type reloc_type = orig_reloc_type; - - 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; - } - - /* No relocation allowed; we must have a constant expression. */ - if (orig_reloc_type == BFD_RELOC_NONE) - { - expressionS exp; - - /* Parse the expression string. */ - saved_line_ptr = input_line_pointer; - input_line_pointer = (char *) exprstr; - expression (&exp); - input_line_pointer = saved_line_ptr; - - /* If we don't have a constant, give an error. */ - if (reloc_type != orig_reloc_type || exp.X_op != O_constant) - as_bad (_("expression must be constant")); - else - value = exp.X_add_number; - return (unsigned long) value; - } - - /* We potentially have a relocation. */ - reloc = nios2_insn_reloc_new (reloc_type, pcrel); - reloc->reloc_next = insn->insn_reloc; - 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. */ - if (nios2_mode == NIOS2_MODE_TEST - && reloc->reloc_expression.X_op == O_constant) - value = reloc->reloc_expression.X_add_number; - - return (unsigned long) value; -} - -/* Encode a 3-bit register number, giving an error if this is not possible. */ -static unsigned int -nios2_assemble_reg3 (const char *token) -{ - struct nios2_reg *reg = nios2_parse_reg (token, REG_3BIT); - int j; - - if (reg == NULL) - return 0; - - for (j = 0; j < nios2_num_r2_reg3_mappings; j++) - if (nios2_r2_reg3_mappings[j] == reg->index) - return j; - - /* Should never get here if we passed validation. */ - as_bad (_("invalid register %s"), token); - return 0; -} - -/* Argument assemble functions. */ - - -/* Control register index. */ -static void -nios2_assemble_arg_c (const char *token, nios2_insn_infoS *insn) -{ - struct nios2_reg *reg = nios2_parse_reg (token, REG_CONTROL); - const struct nios2_opcode *op = insn->insn_nios2_opcode; - - if (reg == NULL) - return; - - switch (op->format) - { - case iw_r_type: - insn->insn_code |= SET_IW_R_IMM5 (reg->index); - break; - case iw_F3X6L5_type: - insn->insn_code |= SET_IW_F3X6L5_IMM5 (reg->index); - break; - default: - bad_opcode (op); - } -} - -/* Destination register. */ -static void -nios2_assemble_arg_d (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned long regtype = REG_NORMAL; - struct nios2_reg *reg; - - if (op->format == iw_custom_type || op->format == iw_F3X8_type) - regtype |= REG_COPROCESSOR; - reg = nios2_parse_reg (token, regtype); - if (reg == NULL) - return; - - switch (op->format) - { - case iw_r_type: - insn->insn_code |= SET_IW_R_C (reg->index); - break; - case iw_custom_type: - insn->insn_code |= SET_IW_CUSTOM_C (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_CUSTOM_READC (0); - else - insn->insn_code |= SET_IW_CUSTOM_READC (1); - break; - case iw_F3X6L5_type: - case iw_F3X6_type: - insn->insn_code |= SET_IW_F3X6L5_C (reg->index); - break; - case iw_F3X8_type: - insn->insn_code |= SET_IW_F3X8_C (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_F3X8_READC (0); - else - insn->insn_code |= SET_IW_F3X8_READC (1); - break; - case iw_F2_type: - insn->insn_code |= SET_IW_F2_B (reg->index); - break; - default: - bad_opcode (op); - } -} - -/* Source register 1. */ -static void -nios2_assemble_arg_s (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned long regtype = REG_NORMAL; - struct nios2_reg *reg; - - if (op->format == iw_custom_type || op->format == iw_F3X8_type) - regtype |= REG_COPROCESSOR; - reg = nios2_parse_reg (token, regtype); - if (reg == NULL) - return; - - switch (op->format) - { - case iw_r_type: - if (op->match == MATCH_R1_JMP && reg->index == 31) - as_bad (_("r31 cannot be used with jmp; use ret instead")); - insn->insn_code |= SET_IW_R_A (reg->index); - break; - case iw_i_type: - insn->insn_code |= SET_IW_I_A (reg->index); - break; - case iw_custom_type: - insn->insn_code |= SET_IW_CUSTOM_A (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_CUSTOM_READA (0); - else - insn->insn_code |= SET_IW_CUSTOM_READA (1); - break; - case iw_F2I16_type: - insn->insn_code |= SET_IW_F2I16_A (reg->index); - break; - case iw_F2X4I12_type: - insn->insn_code |= SET_IW_F2X4I12_A (reg->index); - break; - case iw_F1X4I12_type: - insn->insn_code |= SET_IW_F1X4I12_A (reg->index); - break; - case iw_F1X4L17_type: - insn->insn_code |= SET_IW_F1X4L17_A (reg->index); - break; - case iw_F3X6L5_type: - case iw_F3X6_type: - if (op->match == MATCH_R2_JMP && reg->index == 31) - as_bad (_("r31 cannot be used with jmp; use ret instead")); - insn->insn_code |= SET_IW_F3X6L5_A (reg->index); - break; - case iw_F2X6L10_type: - insn->insn_code |= SET_IW_F2X6L10_A (reg->index); - break; - case iw_F3X8_type: - insn->insn_code |= SET_IW_F3X8_A (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_F3X8_READA (0); - else - insn->insn_code |= SET_IW_F3X8_READA (1); - break; - case iw_F1X1_type: - if (op->match == MATCH_R2_JMPR_N && reg->index == 31) - as_bad (_("r31 cannot be used with jmpr.n; use ret.n instead")); - insn->insn_code |= SET_IW_F1X1_A (reg->index); - break; - case iw_F1I5_type: - /* Implicit stack pointer reference. */ - if (reg->index != 27) - as_bad (_("invalid register %s"), token); - break; - case iw_F2_type: - insn->insn_code |= SET_IW_F2_A (reg->index); - break; - default: - bad_opcode (op); - } -} - -/* Source register 2. */ -static void -nios2_assemble_arg_t (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned long regtype = REG_NORMAL; - struct nios2_reg *reg; - - if (op->format == iw_custom_type || op->format == iw_F3X8_type) - regtype |= REG_COPROCESSOR; - reg = nios2_parse_reg (token, regtype); - if (reg == NULL) - return; - - switch (op->format) - { - case iw_r_type: - insn->insn_code |= SET_IW_R_B (reg->index); - break; - case iw_i_type: - insn->insn_code |= SET_IW_I_B (reg->index); - break; - case iw_custom_type: - insn->insn_code |= SET_IW_CUSTOM_B (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_CUSTOM_READB (0); - else - insn->insn_code |= SET_IW_CUSTOM_READB (1); - break; - case iw_F2I16_type: - insn->insn_code |= SET_IW_F2I16_B (reg->index); - break; - case iw_F2X4I12_type: - insn->insn_code |= SET_IW_F2X4I12_B (reg->index); - break; - case iw_F3X6L5_type: - case iw_F3X6_type: - insn->insn_code |= SET_IW_F3X6L5_B (reg->index); - break; - case iw_F2X6L10_type: - insn->insn_code |= SET_IW_F2X6L10_B (reg->index); - break; - case iw_F3X8_type: - insn->insn_code |= SET_IW_F3X8_B (reg->index); - if (reg->regtype & REG_COPROCESSOR) - insn->insn_code |= SET_IW_F3X8_READB (0); - else - insn->insn_code |= SET_IW_F3X8_READB (1); - break; - case iw_F1I5_type: - insn->insn_code |= SET_IW_F1I5_B (reg->index); - break; - case iw_F2_type: - insn->insn_code |= SET_IW_F2_B (reg->index); - break; - case iw_T1X1I6_type: - /* Implicit zero register reference. */ - if (reg->index != 0) - as_bad (_("invalid register %s"), token); - break; - - default: - bad_opcode (op); - } -} - -/* Destination register w/3-bit encoding. */ -static void -nios2_assemble_arg_D (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - int reg = nios2_assemble_reg3 (token); - - switch (op->format) - { - case iw_T1I7_type: - insn->insn_code |= SET_IW_T1I7_A3 (reg); - break; - case iw_T2X1L3_type: - insn->insn_code |= SET_IW_T2X1L3_B3 (reg); - break; - case iw_T2X1I3_type: - insn->insn_code |= SET_IW_T2X1I3_B3 (reg); - break; - case iw_T3X1_type: - insn->insn_code |= SET_IW_T3X1_C3 (reg); - break; - case iw_T2X3_type: - /* Some instructions using this encoding take 3 register arguments, - requiring the destination register to be the same as the first - source register. */ - if (op->num_args == 3) - insn->insn_code |= SET_IW_T2X3_A3 (reg); - else - insn->insn_code |= SET_IW_T2X3_B3 (reg); - break; - default: - bad_opcode (op); - } -} - -/* Source register w/3-bit encoding. */ -static void -nios2_assemble_arg_S (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - int reg = nios2_assemble_reg3 (token); - - switch (op->format) - { - case iw_T1I7_type: - insn->insn_code |= SET_IW_T1I7_A3 (reg); - break; - case iw_T2I4_type: - insn->insn_code |= SET_IW_T2I4_A3 (reg); - break; - case iw_T2X1L3_type: - insn->insn_code |= SET_IW_T2X1L3_A3 (reg); - break; - case iw_T2X1I3_type: - insn->insn_code |= SET_IW_T2X1I3_A3 (reg); - break; - case iw_T3X1_type: - insn->insn_code |= SET_IW_T3X1_A3 (reg); - break; - case iw_T2X3_type: - /* Some instructions using this encoding take 3 register arguments, - requiring the destination register to be the same as the first - source register. */ - if (op->num_args == 3) - { - int dreg = GET_IW_T2X3_A3 (insn->insn_code); - if (dreg != reg) - as_bad ("source and destination registers must be the same"); - } - else - insn->insn_code |= SET_IW_T2X3_A3 (reg); - break; - case iw_T1X1I6_type: - insn->insn_code |= SET_IW_T1X1I6_A3 (reg); - break; - default: - bad_opcode (op); - } -} - -/* Source register 2 w/3-bit encoding. */ -static void -nios2_assemble_arg_T (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - int reg = nios2_assemble_reg3 (token); - - switch (op->format) - { - case iw_T2I4_type: - insn->insn_code |= SET_IW_T2I4_B3 (reg); - break; - case iw_T3X1_type: - insn->insn_code |= SET_IW_T3X1_B3 (reg); - break; - case iw_T2X3_type: - insn->insn_code |= SET_IW_T2X3_B3 (reg); - break; - default: - bad_opcode (op); - } -} - -/* 16-bit signed immediate. */ -static void -nios2_assemble_arg_i (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_i_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_S16, 0); - insn->constant_bits |= SET_IW_I_IMM16 (val); - break; - case iw_F2I16_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_S16, 0); - insn->constant_bits |= SET_IW_F2I16_IMM16 (val); - break; - default: - bad_opcode (op); - } -} - -/* 12-bit signed immediate. */ -static void -nios2_assemble_arg_I (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_F2X4I12_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_S12, 0); - insn->constant_bits |= SET_IW_F2X4I12_IMM12 (val); - break; - case iw_F1X4I12_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_S12, 0); - insn->constant_bits |= SET_IW_F2X4I12_IMM12 (val); - break; - default: - bad_opcode (op); - } -} - -/* 16-bit unsigned immediate. */ -static void -nios2_assemble_arg_u (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_i_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_U16, 0); - insn->constant_bits |= SET_IW_I_IMM16 (val); - break; - case iw_F2I16_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_U16, 0); - insn->constant_bits |= SET_IW_F2I16_IMM16 (val); - break; - default: - bad_opcode (op); - } -} - -/* 7-bit unsigned immediate with 2-bit shift. */ -static void -nios2_assemble_arg_U (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T1I7_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T1I7_2, 0); - insn->constant_bits |= SET_IW_T1I7_IMM7 (val >> 2); - break; - case iw_X1I7_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_X1I7_2, 0); - insn->constant_bits |= SET_IW_X1I7_IMM7 (val >> 2); - break; - default: - bad_opcode (op); - } -} - -/* 5-bit unsigned immediate with 2-bit shift. */ -static void -nios2_assemble_arg_V (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_F1I5_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_F1I5_2, 0); - insn->constant_bits |= SET_IW_F1I5_IMM5 (val >> 2); - break; - default: - bad_opcode (op); - } -} - -/* 4-bit unsigned immediate with 2-bit shift. */ -static void -nios2_assemble_arg_W (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T2I4_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T2I4_2, 0); - insn->constant_bits |= SET_IW_T2I4_IMM4 (val >> 2); - break; - case iw_L5I4X1_type: - /* This argument is optional for push.n/pop.n, and defaults to - zero if unspecified. */ - if (token == NULL) - return; - - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_L5I4X1, 0); - insn->constant_bits |= SET_IW_L5I4X1_IMM4 (val >> 2); - break; - default: - bad_opcode (op); - } -} - -/* 4-bit unsigned immediate with 1-bit shift. */ -static void -nios2_assemble_arg_X (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T2I4_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T2I4_1, 0); - insn->constant_bits |= SET_IW_T2I4_IMM4 (val >> 1); - break; - default: - bad_opcode (op); - } -} - -/* 4-bit unsigned immediate without shift. */ -static void -nios2_assemble_arg_Y (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T2I4_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T2I4, 0); - insn->constant_bits |= SET_IW_T2I4_IMM4 (val); - break; - default: - bad_opcode (op); - } -} - - -/* 16-bit signed immediate address offset. */ -static void -nios2_assemble_arg_o (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_i_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_16_PCREL, 1); - insn->constant_bits |= SET_IW_I_IMM16 (val); - break; - case iw_F2I16_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_16_PCREL, 1); - insn->constant_bits |= SET_IW_F2I16_IMM16 (val); - break; - default: - bad_opcode (op); - } -} - -/* 10-bit signed address offset with 1-bit shift. */ -static void -nios2_assemble_arg_O (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_I10_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_I10_1_PCREL, 1); - insn->constant_bits |= SET_IW_I10_IMM10 (val >> 1); - break; - default: - bad_opcode (op); - } -} - -/* 7-bit signed address offset with 1-bit shift. */ -static void -nios2_assemble_arg_P (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T1I7_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, 1); - insn->constant_bits |= SET_IW_T1I7_IMM7 (val >> 1); - break; - default: - bad_opcode (op); - } -} - -/* 5-bit unsigned immediate. */ -static void -nios2_assemble_arg_j (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_r_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_IMM5, 0); - insn->constant_bits |= SET_IW_R_IMM5 (val); - break; - case iw_F3X6L5_type: - if (op->match == MATCH_R2_ENI) - /* Value must be constant 0 or 1. */ - { - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - if (val != 0 && val != 1) - as_bad ("invalid eni argument %u", val); - insn->insn_code |= SET_IW_F3X6L5_IMM5 (val); - } - else - { - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_IMM5, 0); - insn->constant_bits |= SET_IW_F3X6L5_IMM5 (val); - } - break; - case iw_F2X6L10_type: - /* Only constant expression without relocation permitted for - bit position. */ - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - if (val > 31) - as_bad ("invalid bit position %u", val); - insn->insn_code |= SET_IW_F2X6L10_MSB (val); - break; - case iw_X2L5_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_X2L5, 0); - insn->constant_bits |= SET_IW_X2L5_IMM5 (val); - break; - default: - bad_opcode (op); - } -} - -/* Second 5-bit unsigned immediate field. */ -static void -nios2_assemble_arg_k (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_F2X6L10_type: - /* Only constant expression without relocation permitted for - bit position. */ - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NONE, 0); - if (val > 31) - as_bad ("invalid bit position %u", val); - else if (GET_IW_F2X6L10_MSB (insn->insn_code) < val) - as_bad ("MSB must be greater than or equal to LSB"); - insn->insn_code |= SET_IW_F2X6L10_LSB (val); - break; - default: - bad_opcode (op); - } -} - -/* 8-bit unsigned immediate. */ -static void -nios2_assemble_arg_l (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_custom_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_IMM8, 0); - insn->constant_bits |= SET_IW_CUSTOM_N (val); - break; - case iw_F3X8_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_IMM8, 0); - insn->constant_bits |= SET_IW_F3X8_N (val); - break; - default: - bad_opcode (op); - } -} - -/* 26-bit unsigned immediate. */ -static void -nios2_assemble_arg_m (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_j_type: - val = nios2_assemble_expression (token, insn, - (nios2_as_options.noat - ? BFD_RELOC_NIOS2_CALL26_NOAT - : BFD_RELOC_NIOS2_CALL26), - 0); - insn->constant_bits |= SET_IW_J_IMM26 (val); - break; - case iw_L26_type: - val = nios2_assemble_expression (token, insn, - (nios2_as_options.noat - ? BFD_RELOC_NIOS2_CALL26_NOAT - : BFD_RELOC_NIOS2_CALL26), - 0); - insn->constant_bits |= SET_IW_L26_IMM26 (val); - break; - default: - bad_opcode (op); - } -} - -/* 6-bit unsigned immediate with no shifting. */ -static void -nios2_assemble_arg_M (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T1X1I6_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T1X1I6, 0); - insn->constant_bits |= SET_IW_T1X1I6_IMM6 (val); - break; - default: - bad_opcode (op); - } -} - -/* 6-bit unsigned immediate with 2-bit shift. */ -static void -nios2_assemble_arg_N (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - - switch (op->format) - { - case iw_T1X1I6_type: - val = nios2_assemble_expression (token, insn, - BFD_RELOC_NIOS2_R2_T1X1I6_2, 0); - insn->constant_bits |= SET_IW_T1X1I6_IMM6 (val >> 2); - break; - default: - bad_opcode (op); - } -} - - -/* Encoded enumeration for addi.n/subi.n. */ -static void -nios2_assemble_arg_e (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - int i; - - switch (op->format) - { - case iw_T2X1I3_type: - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - for (i = 0; i < nios2_num_r2_asi_n_mappings; i++) - if (val == nios2_r2_asi_n_mappings[i]) - break; - if (i == nios2_num_r2_asi_n_mappings) - { - as_bad (_("Invalid constant operand %s"), token); - return; - } - insn->insn_code |= SET_IW_T2X1I3_IMM3 ((unsigned)i); - break; - default: - bad_opcode (op); - } -} - -/* Encoded enumeration for slli.n/srli.n. */ -static void -nios2_assemble_arg_f (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - int i; - - switch (op->format) - { - case iw_T2X1L3_type: - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - for (i = 0; i < nios2_num_r2_shi_n_mappings; i++) - if (val == nios2_r2_shi_n_mappings[i]) - break; - if (i == nios2_num_r2_shi_n_mappings) - { - as_bad (_("Invalid constant operand %s"), token); - return; - } - insn->insn_code |= SET_IW_T2X1L3_SHAMT ((unsigned)i); - break; - default: - bad_opcode (op); - } -} - -/* Encoded enumeration for andi.n. */ -static void -nios2_assemble_arg_g (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - int i; - - switch (op->format) - { - case iw_T2I4_type: - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - for (i = 0; i < nios2_num_r2_andi_n_mappings; i++) - if (val == nios2_r2_andi_n_mappings[i]) - break; - if (i == nios2_num_r2_andi_n_mappings) - { - as_bad (_("Invalid constant operand %s"), token); - return; - } - insn->insn_code |= SET_IW_T2I4_IMM4 ((unsigned)i); - break; - default: - bad_opcode (op); - } -} - -/* Encoded enumeration for movi.n. */ -static void -nios2_assemble_arg_h (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned int val; - int i; - - switch (op->format) - { - case iw_T1I7_type: - val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0); - i = (signed) val; - if ((signed) i == -1) - val = 127; - else if (i == -2) - val = 126; - else if (i == 0xff) - val = 125; - else if (i < 0 || i > 125) - { - as_bad (_("Invalid constant operand %s"), token); - return; - } - insn->insn_code |= SET_IW_T1I7_IMM7 (val); - break; - default: - bad_opcode (op); - } -} - -/* Encoded REGMASK for ldwm/stwm or push.n/pop.n. */ -static void -nios2_assemble_arg_R (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - unsigned long mask; - char *buf = strdup (token); - unsigned long reglist = nios2_parse_reglist (buf, op); - free (buf); - - if (reglist == 0) - return; - - switch (op->format) - { - case iw_F1X4L17_type: - /* Encoding for ldwm/stwm. */ - if (reglist & 0x00003ffc) - mask = reglist >> 2; - else - { - insn->insn_code |= SET_IW_F1X4L17_RS (1); - mask = (reglist & 0x00ffc000) >> 14; - if (reglist & (1 << 28)) - mask |= 1 << 10; - if (reglist & (1u << 31)) - mask |= 1 << 11; - } - insn->insn_code |= SET_IW_F1X4L17_REGMASK (mask); - break; - - case iw_L5I4X1_type: - /* Encoding for push.n/pop.n. */ - if (reglist & (1 << 28)) - insn->insn_code |= SET_IW_L5I4X1_FP (1); - mask = reglist & 0x00ff0000; - if (mask) - { - int i; - - for (i = 0; i < nios2_num_r2_reg_range_mappings; i++) - if (nios2_r2_reg_range_mappings[i] == mask) - break; - if (i == nios2_num_r2_reg_range_mappings) - { - as_bad ("invalid reglist"); - return; - } - insn->insn_code |= SET_IW_L5I4X1_REGRANGE (i); - insn->insn_code |= SET_IW_L5I4X1_CS (1); - } - break; - - default: - bad_opcode (op); - } -} - -/* Base register for ldwm/stwm. */ -static void -nios2_assemble_arg_B (const char *token, nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - int direction, writeback, ret; - char *str = strdup (token); - struct nios2_reg *reg - = nios2_parse_base_register (str, &direction, &writeback, &ret); - - free (str); - if (!reg) - return; - - switch (op->format) - { - case iw_F1X4L17_type: - /* For ldwm, check to see if the base register is already inside the - register list. */ - if (op->match == MATCH_R2_LDWM - && (nios2_reglist_mask & (1 << reg->index))) - { - as_bad ("invalid base register; %s is inside the reglist", reg->name); - return; - } - - /* For stwm, ret option is not allowed. */ - if (op->match == MATCH_R2_STWM && ret) - { - as_bad ("invalid option syntax"); - return; - } - - /* Check that the direction matches the ordering of the reglist. */ - if (nios2_reglist_dir && direction != nios2_reglist_dir) - { - as_bad ("reglist order does not match increment/decrement mode"); - return; - } - - insn->insn_code |= SET_IW_F1X4L17_A (reg->index); - if (direction > 0) - insn->insn_code |= SET_IW_F1X4L17_ID (1); - if (writeback) - insn->insn_code |= SET_IW_F1X4L17_WB (1); - if (ret) - insn->insn_code |= SET_IW_F1X4L17_PC (1); - break; - - default: - bad_opcode (op); - } -} - -static void -nios2_assemble_args (nios2_insn_infoS *insn) -{ - const struct nios2_opcode *op = insn->insn_nios2_opcode; - const char *argptr; - unsigned int tokidx, ntok; - - /* Make sure there are enough arguments. */ - ntok = (op->pinfo & NIOS2_INSN_OPTARG) ? op->num_args - 1 : op->num_args; - for (tokidx = 1; tokidx <= ntok; tokidx++) - if (insn->insn_tokens[tokidx] == NULL) - { - as_bad ("missing argument"); - return; - } - - for (argptr = op->args, tokidx = 1; - *argptr && insn->insn_tokens[tokidx]; - argptr++) - switch (*argptr) - { - case ',': - case '(': - case ')': - break; - - case 'c': - nios2_assemble_arg_c (insn->insn_tokens[tokidx++], insn); - break; - - case 'd': - nios2_assemble_arg_d (insn->insn_tokens[tokidx++], insn); - break; - - case 's': - nios2_assemble_arg_s (insn->insn_tokens[tokidx++], insn); - break; - - case 't': - nios2_assemble_arg_t (insn->insn_tokens[tokidx++], insn); - break; - - case 'D': - nios2_assemble_arg_D (insn->insn_tokens[tokidx++], insn); - break; - - case 'S': - nios2_assemble_arg_S (insn->insn_tokens[tokidx++], insn); - break; - - case 'T': - nios2_assemble_arg_T (insn->insn_tokens[tokidx++], insn); - break; - - case 'i': - nios2_assemble_arg_i (insn->insn_tokens[tokidx++], insn); - break; - - case 'I': - nios2_assemble_arg_I (insn->insn_tokens[tokidx++], insn); - break; - - case 'u': - nios2_assemble_arg_u (insn->insn_tokens[tokidx++], insn); - break; - - case 'U': - nios2_assemble_arg_U (insn->insn_tokens[tokidx++], insn); - break; - - case 'V': - nios2_assemble_arg_V (insn->insn_tokens[tokidx++], insn); - break; - - case 'W': - nios2_assemble_arg_W (insn->insn_tokens[tokidx++], insn); - break; - - case 'X': - nios2_assemble_arg_X (insn->insn_tokens[tokidx++], insn); - break; - - case 'Y': - nios2_assemble_arg_Y (insn->insn_tokens[tokidx++], insn); - break; - - case 'o': - nios2_assemble_arg_o (insn->insn_tokens[tokidx++], insn); - break; - - case 'O': - nios2_assemble_arg_O (insn->insn_tokens[tokidx++], insn); - break; - - case 'P': - nios2_assemble_arg_P (insn->insn_tokens[tokidx++], insn); - break; - - case 'j': - nios2_assemble_arg_j (insn->insn_tokens[tokidx++], insn); - break; - - case 'k': - nios2_assemble_arg_k (insn->insn_tokens[tokidx++], insn); - break; - - case 'l': - nios2_assemble_arg_l (insn->insn_tokens[tokidx++], insn); - break; - - case 'm': - nios2_assemble_arg_m (insn->insn_tokens[tokidx++], insn); - break; - - case 'M': - nios2_assemble_arg_M (insn->insn_tokens[tokidx++], insn); - break; - - case 'N': - nios2_assemble_arg_N (insn->insn_tokens[tokidx++], insn); - break; - - case 'e': - nios2_assemble_arg_e (insn->insn_tokens[tokidx++], insn); - break; - - case 'f': - nios2_assemble_arg_f (insn->insn_tokens[tokidx++], insn); - break; - - case 'g': - nios2_assemble_arg_g (insn->insn_tokens[tokidx++], insn); - break; - - case 'h': - nios2_assemble_arg_h (insn->insn_tokens[tokidx++], insn); - break; - - case 'R': - nios2_assemble_arg_R (insn->insn_tokens[tokidx++], insn); - break; - - case 'B': - nios2_assemble_arg_B (insn->insn_tokens[tokidx++], insn); - break; - - default: - bad_opcode (op); - break; - } - - /* Perform argument checking. */ - nios2_check_assembly (insn->insn_code | insn->constant_bits, - insn->insn_tokens[tokidx]); -} - - -/* 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 (char *argstr, const char *parsestr) -{ - char *temp; - - switch (*parsestr) - { - case 'c': - case 'd': - case 's': - case 't': - case 'D': - case 'S': - case 'T': - 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 'I': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'O': - case 'P': - case 'e': - case 'f': - case 'g': - case 'h': - case 'M': - case 'N': - - /* We can't have %hi, %lo or %hiadj here. */ - if (*argstr == '%') - as_bad (_("badly formed expression near %s"), argstr); - break; - - case 'R': - /* Register list for ldwm/stwm or push.n/pop.n. Replace the commas - in the list with spaces so we don't confuse them with separators. */ - if (*argstr != '{') - { - as_bad ("missing '{' in register list"); - break; - } - for (temp = argstr + 1; *temp; temp++) - { - if (*temp == '}') - break; - else if (*temp == ',') - *temp = ' '; - } - if (!*temp) - { - as_bad ("missing '}' in register list"); - break; - } - break; - - case 'B': - /* Base register and options for ldwm/stwm. This is the final argument - and consumes the rest of the argument string; replace commas - with spaces so that the token splitter doesn't think they are - separate arguments. */ - for (temp = argstr; *temp; temp++) - if (*temp == ',') - *temp = ' '; - break; - - case 'o': - case 'E': - break; - default: - BAD_CASE (*parsestr); - 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; - 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; - bool 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 (p, parsestr); - ++parsestr; - while (*parsestr == '(' || *parsestr == ')' || *parsestr == ',') - { - char *context = p; - p = nios2_consume_separator (p, parsestr); - /* Check for missing separators. */ - if (!p && !(insn->insn_nios2_opcode->pinfo & NIOS2_INSN_OPTARG)) - { - as_bad (_("expecting %c near %s"), *parsestr, context); - break; - } - ++parsestr; - } - - if (*parsestr == '\0') - { - /* Check that the argument string has no trailing arguments. */ - 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; -} - - - -/** 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] = concat (tmp, modifier, (char *) NULL); -} - -/* 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] = concat ("~(", tmp, ")+1", (char *) NULL); -} - -/* 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) -{ - 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) -{ - - const struct nios2_opcode *op = insn->insn_nios2_opcode; - nios2_ps_insn_infoS *ps_insn; - unsigned int tokidx, ntok; - - /* Find which real insn the pseudo-op translates to and - switch the insn_info ptr to point to it. */ - ps_insn = nios2_ps_lookup (op->name); - - if (ps_insn != NULL) - { - insn->insn_nios2_opcode = nios2_opcode_lookup (ps_insn->insn); - insn->insn_tokens[0] = insn->insn_nios2_opcode->name; - - /* Make sure there are enough arguments. */ - ntok = ((op->pinfo & NIOS2_INSN_OPTARG) - ? op->num_args - 1 : op->num_args); - for (tokidx = 1; tokidx <= ntok; tokidx++) - if (insn->insn_tokens[tokidx] == NULL) - { - as_bad ("missing argument"); - return NULL; - } - - /* 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"), - insn->insn_nios2_opcode->name); - 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}, - {"nop.n", "mov.n", nios2_append_arg, "zero", 2, 1, NULL} - /* 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. */ - -/* Output a normal instruction. */ -static void -output_insn (nios2_insn_infoS *insn) -{ - char *f; - nios2_insn_relocS *reloc; - f = frag_more (insn->insn_nios2_opcode->size); - /* This allocates enough space for the instruction - and puts it in the current frag. */ - md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size); - /* Emit debug info. */ - dwarf2_emit_insn (insn->insn_nios2_opcode->size); - /* 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, - insn->insn_nios2_opcode->size, - &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; - bool is_cdx = (insn->insn_nios2_opcode->size == 2); - - /* 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, insn->insn_nios2_opcode->size, - (is_cdx ? CDX_UBRANCH_SUBTYPE (0) : UBRANCH_SUBTYPE (0)), - symp, offset, NULL); - - md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size); - - /* 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; - bool is_cdx = (insn->insn_nios2_opcode->size == 2); - - /* 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, insn->insn_nios2_opcode->size, - (is_cdx ? CDX_CBRANCH_SUBTYPE (0) : CBRANCH_SUBTYPE (0)), - symp, offset, NULL); - - md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size); - - /* 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; - const struct nios2_opcode *op = insn->insn_nios2_opcode; - - switch (op->format) - { - case iw_j_type: - md_number_to_chars (f, - (MATCH_R1_ORHI | SET_IW_I_B (AT_REGNUM) - | SET_IW_I_A (0)), - 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, - (MATCH_R1_ORI | SET_IW_I_B (AT_REGNUM) - | SET_IW_I_A (AT_REGNUM)), - 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, MATCH_R1_CALLR | SET_IW_R_A (AT_REGNUM), 4); - dwarf2_emit_insn (4); - break; - case iw_L26_type: - md_number_to_chars (f, - (MATCH_R2_ORHI | SET_IW_F2I16_B (AT_REGNUM) - | SET_IW_F2I16_A (0)), - 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, - (MATCH_R2_ORI | SET_IW_F2I16_B (AT_REGNUM) - | SET_IW_F2I16_A (AT_REGNUM)), - 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, MATCH_R2_CALLR | SET_IW_F3X6L5_A (AT_REGNUM), - 4); - dwarf2_emit_insn (4); - break; - default: - bad_opcode (op); - } -} - -/* 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, code = 0; - const struct nios2_opcode *op = insn->insn_nios2_opcode; - - /* If the reloc is NULL, there was an error assembling the movia. */ - if (reloc != NULL) - { - switch (op->format) - { - case iw_i_type: - reg = GET_IW_I_B (insn->insn_code); - code = MATCH_R1_ADDI | SET_IW_I_A (reg) | SET_IW_I_B (reg); - break; - case iw_F2I16_type: - reg = GET_IW_F2I16_B (insn->insn_code); - code = MATCH_R2_ADDI | SET_IW_F2I16_A (reg) | SET_IW_F2I16_B (reg); - break; - default: - bad_opcode (op); - } - - md_number_to_chars (f, insn->insn_code, 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); - md_number_to_chars (f + 4, code, 4); - dwarf2_emit_insn (4); - 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. */ - -/* Update the selected architecture based on ARCH, giving an error if - ARCH is an invalid value. */ - -static void -nios2_use_arch (const char *arch) -{ - if (strcmp (arch, "nios2") == 0 || strcmp (arch, "r1") == 0) - { - nios2_architecture |= EF_NIOS2_ARCH_R1; - nios2_opcodes = (struct nios2_opcode *) nios2_r1_opcodes; - nios2_num_opcodes = nios2_num_r1_opcodes; - nop32 = nop_r1; - nop16 = NULL; - return; - } - else if (strcmp (arch, "r2") == 0) - { - nios2_architecture |= EF_NIOS2_ARCH_R2; - nios2_opcodes = (struct nios2_opcode *) nios2_r2_opcodes; - nios2_num_opcodes = nios2_num_r2_opcodes; - nop32 = nop_r2; - nop16 = nop_r2_cdx; - return; - } - - as_bad (_("unknown architecture '%s'"), arch); -} - -/* The following functions are called by machine-independent parts of - the assembler. */ -int -md_parse_option (int c, const 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; - case OPTION_MARCH: - nios2_use_arch (arg); - 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" - " -march=ARCH enable instructions from architecture ARCH\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; - - switch (nios2_architecture) - { - default: - case EF_NIOS2_ARCH_R1: - bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r1); - break; - case EF_NIOS2_ARCH_R2: - if (target_big_endian) - as_fatal (_("Big-endian R2 is not supported.")); - bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r2); - break; - } - - /* Create and fill a hashtable for the Nios II opcodes, registers and - arguments. */ - nios2_opcode_hash = str_htab_create (); - nios2_reg_hash = str_htab_create (); - nios2_ps_hash = str_htab_create (); - - for (i = 0; i < nios2_num_opcodes; ++i) - if (str_hash_insert (nios2_opcode_hash, nios2_opcodes[i].name, - &nios2_opcodes[i], 0) != NULL) - as_fatal (_("duplicate %s"), nios2_opcodes[i].name); - - for (i = 0; i < nios2_num_regs; ++i) - if (str_hash_insert (nios2_reg_hash, nios2_regs[i].name, - &nios2_regs[i], 0) != NULL) - as_fatal (_("duplicate %s"), nios2_regs[i].name); - - for (i = 0; i < nios2_num_ps_insn_info_structs; ++i) - if (str_hash_insert (nios2_ps_hash, - nios2_ps_insn_info_structs[i].pseudo_insn, - &nios2_ps_insn_info_structs[i], 0) != NULL) - as_fatal (_("duplicate %s"), nios2_ps_insn_info_structs[i].pseudo_insn); - - /* Assembler option defaults. */ - nios2_as_options.noat = false; - nios2_as_options.nobreak = false; - - /* Initialize the alignment data. */ - nios2_current_align_seg = now_seg; - nios2_last_label = NULL; - nios2_current_align = 0; - nios2_min_align = 2; -} - - -/* Assembles a single line of Nios II assembly language. */ -void -md_assemble (char *op_str) -{ - char *argstr; - char *op_strdup = NULL; - unsigned long saved_pinfo = 0; - nios2_insn_infoS thisinsn; - nios2_insn_infoS *insn = &thisinsn; - bool ps_error = false; - - /* Make sure we are aligned on an appropriate boundary. */ - if (nios2_current_align < nios2_min_align) - nios2_align (nios2_min_align, NULL, nios2_last_label); - else if (nios2_current_align > nios2_min_align) - nios2_current_align = nios2_min_align; - 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; - - /* Note if we've seen a 16-bit instruction. */ - if (insn->insn_nios2_opcode->size == 2) - nios2_min_align = 1; - - /* Set the opcode for the instruction. */ - insn->insn_code = insn->insn_nios2_opcode->match; - insn->constant_bits = 0; - - /* 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); - if (!ps_insn) - ps_error = true; - } - - /* If we found invalid pseudo-instruction syntax, the error's already - been diagnosed in nios2_translate_pseudo_insn, so skip - remaining processing. */ - if (!ps_error) - { - /* Assemble the parsed arguments into the instruction word. */ - nios2_assemble_args (insn); - - /* Handle relaxation and other transformations. */ - 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) - || (insn->insn_reloc->reloc_type - == BFD_RELOC_NIOS2_CALL26_NOAT))) - output_call (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 - /* 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 - || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_LO - || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_HA - || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_LO - || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_HA - ) - 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 = XNEW (arelent); - reloc->sym_ptr_ptr = XNEW (asymbol *); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->addend = fixp->fx_offset; /* 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 (void) -{ - /* 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, - &zero_address_frag, 0); - } - - 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 *) nop32; - 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, const 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(...) and - %gotoff(...). */ -bfd_reloc_code_real_type -nios2_cons (expressionS *exp, int size) -{ - bfd_reloc_code_real_type explicit_reloc = BFD_RELOC_NONE; - const char *reloc_name = NULL; - - SKIP_WHITESPACE (); - if (input_line_pointer[0] == '%') - { - if (startswith (input_line_pointer + 1, "tls_ldo")) - { - reloc_name = "%tls_ldo"; - if (size != 4) - as_bad (_("Illegal operands: %%tls_ldo in %d-byte data field"), - size); - else - { - input_line_pointer += 8; - explicit_reloc = BFD_RELOC_NIOS2_TLS_DTPREL; - } - } - else if (startswith (input_line_pointer + 1, "gotoff")) - { - reloc_name = "%gotoff"; - if (size != 4) - as_bad (_("Illegal operands: %%gotoff in %d-byte data field"), - size); - else - { - input_line_pointer += 7; - explicit_reloc = BFD_RELOC_NIOS2_GOTOFF; - } - } - - if (explicit_reloc != BFD_RELOC_NONE) - { - SKIP_WHITESPACE (); - if (input_line_pointer[0] != '(') - as_bad (_("Illegal operands: %s requires arguments in ()"), - reloc_name); - 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: %s requires arguments in ()"), - reloc_name); - else - { - *end = '\0'; - expression (exp); - *end = c; - if (input_line_pointer != end) - as_bad (_("Illegal operands: %s requires arguments in ()"), - reloc_name); - else - { - input_line_pointer++; - SKIP_WHITESPACE (); - c = *input_line_pointer; - if (! is_end_of_line[c] && c != ',') - as_bad (_("Illegal operands: garbage after %s()"), - reloc_name); - } - } - } - } - } - if (explicit_reloc == BFD_RELOC_NONE) - expression (exp); - return explicit_reloc; -} - -/* 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); -} - -#ifdef OBJ_ELF -/* Some special processing for a Nios II ELF file. */ - -void -nios2_elf_final_processing (void) -{ - elf_elfheader (stdoutput)->e_flags = nios2_architecture; -} -#endif diff --git a/gas/config/tc-nios2.h b/gas/config/tc-nios2.h deleted file mode 100644 index bc78d55cf6d..00000000000 --- a/gas/config/tc-nios2.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Definitions for Altera Nios II assembler. - Copyright (C) 2012-2024 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 instruct in 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, const 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 - -/* Don't allow the generic code to convert fixups involving the - subtraction of a label in the current section to pc-relative if we - don't have the necessary pc-relative relocation. */ -#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \ - (!((FIX)->fx_r_type == BFD_RELOC_16 \ - || (FIX)->fx_r_type == BFD_RELOC_NIOS2_LO16 \ - || (FIX)->fx_r_type == BFD_RELOC_NIOS2_HIADJ16)) - -/* 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 bfd_reloc_code_real_type nios2_cons (expressionS *exp, int size); - -/* 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); - -#define elf_tc_final_processing nios2_elf_final_processing -extern void nios2_elf_final_processing (void); - -#endif /* TC_NIOS2 */ diff --git a/gas/configure.tgt b/gas/configure.tgt index d58f21873a3..d91787342c7 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -347,8 +347,6 @@ case ${generic_target} in nds32-*-elf*) fmt=elf ;; nds32-*-linux*) fmt=elf em=linux ;; - 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/all.texi b/gas/doc/all.texi index 815909c7cd7..f297a122f48 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -57,7 +57,6 @@ @set MMIX @set MS1 @set MSP430 -@set NIOSII @set NDS32 @set NS32K @set OPENRISC diff --git a/gas/doc/as.texi b/gas/doc/as.texi index a5535845e40..725029c867d 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -496,12 +496,6 @@ 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 NDS32 @emph{Target NDS32 options:} @@ -1328,24 +1322,6 @@ 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, @@ -8173,9 +8149,6 @@ subject, see the hardware manufacturer's manual. @ifset NDS32 * NDS32-Dependent:: Andes NDS32 Dependent Features @end ifset -@ifset NIOSII -* NiosII-Dependent:: Altera Nios II Dependent Features -@end ifset @ifset NS32K * NS32K-Dependent:: NS32K Dependent Features @end ifset @@ -8413,10 +8386,6 @@ family. @include c-nds32.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 deleted file mode 100644 index abdd56167b7..00000000000 --- a/gas/doc/c-nios2.texi +++ /dev/null @@ -1,267 +0,0 @@ -@c Copyright (C) 2012-2024 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. - -@cindex @code{march} command-line option, Nios II -@item -march=@var{architecture} -This option specifies the target architecture. The assembler issues -an error message if an attempt is made to assemble an instruction which -will not execute on the target architecture. The following architecture -names are recognized: -@code{r1}, -@code{r2}. -The default is @code{r1}. - -@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{call_lo} directive, Nios II -@cindex @code{call_hiadj} directive, Nios II -@cindex @code{got} directive, Nios II -@cindex @code{got_lo} directive, Nios II -@cindex @code{got_hiadj} 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}) -@item %call_lo(@var{expression}) -@item %call_hiadj(@var{expression}) -@itemx %got(@var{expression}) -@itemx %got_lo(@var{expression}) -@itemx %got_hiadj(@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/doc/local.mk b/gas/doc/local.mk index c83b98a779d..397b4143c74 100644 --- a/gas/doc/local.mk +++ b/gas/doc/local.mk @@ -74,7 +74,6 @@ CPU_DOCS = \ %D%/c-mmix.texi \ %D%/c-mt.texi \ %D%/c-msp430.texi \ - %D%/c-nios2.texi \ %D%/c-nds32.texi \ %D%/c-ns32k.texi \ %D%/c-or1k.texi \ diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index 5fff61f86ed..09073241ef8 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -398,7 +398,6 @@ if { ![istarget avr-*-*] && ![istarget dlx-*-*] && ![istarget hppa*-*-*] && ![istarget m68k-*-*] - && ![istarget nios2-*-*] && ![istarget pj-*-*] && ![istarget sh*-*-*] && ![istarget *c4x-*-*] diff --git a/gas/testsuite/gas/nios2/add-r2.d b/gas/testsuite/gas/nios2/add-r2.d deleted file mode 100644 index 99582431fe7..00000000000 --- a/gas/testsuite/gas/nios2/add-r2.d +++ /dev/null @@ -1,18 +0,0 @@ -#objdump: -dr --prefix-addresses --show-raw-insn -#name: NIOS2 R2 add -#as: -march=r2 -#source: add.s - -# Test the add instruction - -.*: +file format elf32-littlenios2 - -Disassembly of section .text: -0+0000 <[^>]*> c4042120 add r4,r4,r4 -0+0004 <[^>]*> 7fff2104 addi r4,r4,32767 -0+0008 <[^>]*> 80002104 addi r4,r4,-32768 -0+000c <[^>]*> 00002104 addi r4,r4,0 -0+0010 <[^>]*> ffff2104 addi r4,r4,-1 -0+0014 <[^>]*> ffff2104 addi r4,r4,-1 -0+0018 <[^>]*> 34562104 addi r4,r4,13398 -0+001c <[^>]*> c4000020 nop diff --git a/gas/testsuite/gas/nios2/add.d b/gas/testsuite/gas/nios2/add.d deleted file mode 100644 index 3eb685ada03..00000000000 --- a/gas/testsuite/gas/nios2/add.d +++ /dev/null @@ -1,16 +0,0 @@ -#objdump: -dr --prefix-addresses --show-raw-insn -#name: NIOS2 add - -# Test the add instruction - -.*: +file format elf32-littlenios2 - -Disassembly of section .text: -0+0000 <[^>]*> 2109883a add r4,r4,r4 -0+0004 <[^>]*> 211fffc4 addi r4,r4,32767 -0+0008 <[^>]*> 21200004 addi r4,r4,-32768 -0+000c <[^>]*> 21000004 addi r4,r4,0 -0+0010 <[^>]*> 213fffc4 addi r4,r4,-1 -0+0014 <[^>]*> 213fffc4 addi r4,r4,-1 -0+0018 <[^>]*> 210d1584 addi r4,r4,13398 -0+001c <[^>]*> 0001883a nop diff --git a/gas/testsuite/gas/nios2/add.s b/gas/testsuite/gas/nios2/add.s deleted file mode 100644 index 5b72a82741d..00000000000 --- a/gas/testsuite/gas/nios2/add.s +++ /dev/null @@ -1,13 +0,0 @@ -# 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-r2.d b/gas/testsuite/gas/nios2/align_fill-r2.d deleted file mode 100644 index 8e99882c01f..00000000000 --- a/gas/testsuite/gas/nios2/align_fill-r2.d +++ /dev/null @@ -1,25 +0,0 @@ -#objdump: -dr --prefix-addresses --show-raw-insn -#name: NIOS2 R2 align_fill -#as: -march=r2 -#source: align_fill.s - -# Test the and macro. - -.*: +file format elf32-littlenios2 - -Disassembly of section .text: -0+0000 <[^>]*> fff8dec4 addi sp,sp,-8 -0+0004 <[^>]*> 0004e6f7 stw fp,4\(sp\) -0+0008 <[^>]*> c41c06e0 mov fp,sp -0+000c <[^>]*> c4030020 mov r3,zero -0+0010 <[^>]*> c4000020 nop -0+0014 <[^>]*> c4000020 nop -0+0018 <[^>]*> c4000020 nop -0+001c <[^>]*> c4000020 nop -0+0020 <[^>]*> 000118c4 addi r3,r3,1 -0+0024 <[^>]*> 006410de cmplti r2,r3,100 -0+0028 <[^>]*> fff400a2 bne r2,zero,00000020 <[^>]*> -0+002c <[^>]*> 0004e6d7 ldw fp,4\(sp\) -0+0030 <[^>]*> 0008dec4 addi sp,sp,8 -0+0034 <[^>]*> 140007e0 ret - ... diff --git a/gas/testsuite/gas/nios2/align_fill.d b/gas/testsuite/gas/nios2/align_fill.d deleted file mode 100644 index ecee94d4411..00000000000 --- a/gas/testsuite/gas/nios2/align_fill.d +++ /dev/null @@ -1,23 +0,0 @@ -#objdump: -dr --prefix-addresses --show-raw-insn -#name: NIOS2 align_fill - -# Test the and macro. - -.*: +file format elf32-littlenios2 - -Disassembly of section .text: -0+0000 <[^>]*> defffe04 addi sp,sp,-8 -0+0004 <[^>]*> df000115 stw fp,4\(sp\) -0+0008 <[^>]*> d839883a mov fp,sp -0+000c <[^>]*> 0007883a mov r3,zero -0+0010 <[^>]*> 0001883a nop -0+0014 <[^>]*> 0001883a nop -0+0018 <[^>]*> 0001883a nop -0+001c <[^>]*> 0001883a nop -0+0020 <[^>]*> 18c00044 addi r3,r3,1 -0+0024 <[^>]*> 18801910 cmplti r2,r3,100 -0+0028 <[^>]*> 103ffd1e bne r2,zero,00000020 <[^>]*> -0+002c <[^>]*> df000117 ldw fp,4\(sp\) -0+0030 <[^>]*> dec00204 addi sp,sp,8 -0+0034 <[^>]*> f800283a ret - ... diff --git a/gas/testsuite/gas/nios2/align_fill.s b/gas/testsuite/gas/nios2/align_fill.s deleted file mode 100644 index 56838395465..00000000000 --- a/gas/testsuite/gas/nios2/align_fill.s +++ /dev/null @@ -1,20 +0,0 @@ - .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-r2.d b/gas/testsuite/gas/nios2/align_text-r2.d deleted file mode 100644 index a2f32d954fa..00000000000 --- a/gas/testsuite/gas/nios2/align_text-r2.d +++ /dev/null @@ -1,24 +0,0 @@ -#objdump: -dr -#name: NIOS2 R2 align_test -#as: -march=r2 -#source: align_text.s - -# Test alignment in text sections. - -.*: +file format elf32-littlenios2 - -Disassembly of section .text: -00000000 : - 0: 00000000 call 0 - 4: c4000020 nop - 8: c4000020 nop - c: c4000020 nop - 10: c4000020 nop - 14: c4000020 nop - 18: c4000020 nop - 1c: c4000020 nop - -00000020