From 97d368012fda0b1050a85e1d8d86b28430f34f23 Mon Sep 17 00:00:00 2001 From: Frans Meulenbroeks Date: Fri, 9 Jul 2010 18:23:22 +0200 Subject: binutils 2.20.1: added patches to support nios2 Signed-off-by: Frans Meulenbroeks --- .../binutils-2.20.1/binutils-nios2-files.patch | 41026 +++++++++++++++++++ .../binutils/binutils-2.20.1/binutils-nios2.patch | 650 + recipes/binutils/binutils_2.20.1.bb | 5 + 3 files changed, 41681 insertions(+) create mode 100644 recipes/binutils/binutils-2.20.1/binutils-nios2-files.patch create mode 100644 recipes/binutils/binutils-2.20.1/binutils-nios2.patch (limited to 'recipes/binutils') diff --git a/recipes/binutils/binutils-2.20.1/binutils-nios2-files.patch b/recipes/binutils/binutils-2.20.1/binutils-nios2-files.patch new file mode 100644 index 0000000000..0601aebc3e --- /dev/null +++ b/recipes/binutils/binutils-2.20.1/binutils-nios2-files.patch @@ -0,0 +1,41026 @@ +Index: binutils-2.20.1/bfd/cpu-nios2.c +=================================================================== +--- /dev/null ++++ binutils-2.20.1/bfd/cpu-nios2.c +@@ -0,0 +1,71 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* bfd back-end for Altera Nios II support ++ ++ Copyright (C) 2003 ++ by Nigel Gray (ngray@altera.com). ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++ ++static const bfd_arch_info_type *nios2_compatible ++ (const bfd_arch_info_type *, const bfd_arch_info_type *); ++ ++/* The default routine tests bits_per_word, which is wrong on mips as ++ mips word size doesn't correlate with reloc size. */ ++ ++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; ++ ++ /* Machine compatibility is checked in ++ _bfd_mips_elf_merge_private_bfd_data. */ ++ ++ return a; ++} ++ ++#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ ++ { \ ++ BITS_WORD, /* bits in a word */ \ ++ BITS_ADDR, /* bits in an address */ \ ++ 8, /* 8 bits in a byte */ \ ++ bfd_arch_nios2, \ ++ NUMBER, \ ++ "nios2", \ ++ PRINT, \ ++ 3, \ ++ DEFAULT, \ ++ nios2_compatible, \ ++ bfd_default_scan, \ ++ NEXT, \ ++ } ++ ++#define NN(index) (&arch_info_struct[(index) + 1]) ++ ++static const bfd_arch_info_type arch_info_struct[] = ++{ ++ N (32, 32, bfd_mach_nios2, "nios2", FALSE, 0), ++}; ++ ++/* There is only one architecture - but we give the default a machine number of 0 ++ so the linker can distinguish it */ ++const bfd_arch_info_type bfd_nios2_arch = ++N (32, 32, 0, "nios2", TRUE, &arch_info_struct[0]); +Index: binutils-2.20.1/bfd/elf32-nios2.c +=================================================================== +--- /dev/null ++++ binutils-2.20.1/bfd/elf32-nios2.c +@@ -0,0 +1,5003 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* New Jersey-specific support for 32-bit ELF ++ ++ Copyright (C) 2005 ++ by Nigel Gray (ngray@altera.com). ++ ++ Copyright (C) 2008, CodeSourcery Inc. ++ ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* This file handles Altera New Jersey ELF targets */ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "bfdlink.h" ++#include "genlink.h" ++#include "elf-bfd.h" ++#include "elf/nios2.h" ++#include "opcode/nios2.h" ++ ++/* Use RELA relocations. */ ++#ifndef USE_RELA ++#define USE_RELA ++#endif ++ ++#ifdef USE_REL ++#undef USE_REL ++#endif ++ ++/* Function prototypes. */ ++ ++static reloc_howto_type *nios2_elf32_bfd_reloc_type_lookup ++ (bfd *, bfd_reloc_code_real_type); ++ ++static bfd_boolean nios2_elf32_relax_section ++ (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); ++#if 0 ++static bfd_boolean nios2_elf32_relax_delete_bytes ++ (bfd *, asection *, bfd_vma, int); ++#endif ++static reloc_howto_type *nios2_elf32_rtype_to_howto ++ (unsigned int r_type, bfd_boolean rela_p); ++ ++static void nios2_elf32_info_to_howto ++ (bfd * abfd, arelent * cache_ptr, Elf_Internal_Rela * dst); ++ ++static bfd_boolean nios2_elf32_relocate_section ++ (bfd * output_bfd, struct bfd_link_info * info, bfd * input_bfd, ++ asection * input_section, bfd_byte * contents, ++ Elf_Internal_Rela * relocs, Elf_Internal_Sym * local_syms, ++ asection ** local_sections); ++ ++static reloc_howto_type *lookup_howto (unsigned int rtype); ++ ++static bfd_reloc_status_type nios2_elf_final_gp ++ (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *, ++ struct bfd_link_info *); ++ ++static bfd_boolean nios2_elf_assign_gp ++ (bfd *, bfd_vma *, struct bfd_link_info *); ++ ++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 **); ++ ++static bfd_reloc_status_type nios2_elf32_do_hi16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_lo16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_hiadj16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_pcrel_lo16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_pcrel_hiadj16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_pcrel16_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_call26_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_gprel_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_ujmp_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_cjmp_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_reloc_status_type nios2_elf32_do_callr_relocate ++ (bfd *, reloc_howto_type *, asection *, ++ bfd_byte *, bfd_vma, bfd_vma, bfd_vma); ++ ++static bfd_boolean nios2_elf32_section_from_shdr ++ (bfd *, Elf_Internal_Shdr *, const char *name, int shindex); ++ ++static bfd_boolean nios2_elf32_section_flags ++ (flagword *, const Elf_Internal_Shdr *); ++ ++static bfd_boolean nios2_elf32_fake_sections ++ (bfd *, Elf_Internal_Shdr *, asection *); ++ ++ ++ ++static bfd_boolean nios2_elf32_check_relocs ++ (bfd *, struct bfd_link_info *, asection *, ++ const Elf_Internal_Rela *); ++ ++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); ++ ++void ++_bfd_set_link_info (struct bfd_link_info *info); ++ ++void ++_bfd_set_force_make_executable (bfd_boolean force); ++ ++ ++/* Target vector. */ ++extern const bfd_target bfd_elf32_littlenios2_vec; ++extern const bfd_target bfd_elf32_bignios2_vec; ++ ++/* Offset of tp and dtp pointers from start of TLS block. */ ++#define TP_OFFSET 0x7000 ++#define DTP_OFFSET 0x8000 ++ ++/* The relocation table used for SHT_REL sections. */ ++ ++static reloc_howto_type elf_nios2_howto_table_rel[] = { ++ /* No relocation. */ ++ HOWTO (R_NIOS2_NONE, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_NIOS2_NONE", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit signed immediate relocation */ ++ HOWTO (R_NIOS2_S16, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 6, /* bitpos */ ++ complain_overflow_signed, /* complain on overflow */ ++ bfd_elf_generic_reloc, /* special function */ ++ "R_NIOS2_S16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0x003fffc0, /* src_mask */ ++ 0x003fffc0, /* dest_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit unsigned immediate relocation */ ++ HOWTO (R_NIOS2_U16, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 6, /* bitpos */ ++ complain_overflow_unsigned, /* complain on overflow */ ++ bfd_elf_generic_reloc, /* special function */ ++ "R_NIOS2_U16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0x003fffc0, /* src_mask */ ++ 0x003fffc0, /* dest_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ HOWTO (R_NIOS2_PCREL16, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 6, /* bitpos */ ++ complain_overflow_signed, /* complain on overflow */ ++ nios2_elf32_pcrel16_relocate, /* special function */ ++ "R_NIOS2_PCREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0x003fffc0, /* src_mask */ ++ 0x003fffc0, /* dest_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ HOWTO (R_NIOS2_CALL26, /* type */ ++ 2, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 6, /* bitpos */ ++ complain_overflow_dont, /* complain on overflow */ ++ nios2_elf32_call26_relocate, /* special function */ ++ "R_NIOS2_CALL26", /* name */ ++ FALSE, /* partial_inplace */ ++ 0xffffffc0, /* src_mask */ ++ 0xffffffc0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ HOWTO (R_NIOS2_IMM5, ++ 0, ++ 2, ++ 5, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_IMM5", ++ FALSE, ++ 0x000007c0, ++ 0x000007c0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_CACHE_OPX, ++ 0, ++ 2, ++ 5, ++ FALSE, ++ 22, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_CACHE_OPX", ++ FALSE, ++ 0x07c00000, ++ 0x07c00000, ++ FALSE), ++ ++ HOWTO (R_NIOS2_IMM6, ++ 0, ++ 2, ++ 6, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_IMM6", ++ FALSE, ++ 0x00000fc0, ++ 0x00000fc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_IMM8, ++ 0, ++ 2, ++ 8, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_IMM8", ++ FALSE, ++ 0x00003fc0, ++ 0x00003fc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_HI16, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_hi16_relocate, ++ "R_NIOS2_HI16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_LO16, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_lo16_relocate, ++ "R_NIOS2_LO16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_HIADJ16, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_hiadj16_relocate, ++ "R_NIOS2_HIADJ16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_BFD_RELOC_32, ++ 0, ++ 2, /* long */ ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_BFD_RELOC32", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_BFD_RELOC_16, ++ 0, ++ 1, /* short */ ++ 16, ++ FALSE, ++ 0, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_BFD_RELOC16", ++ FALSE, ++ 0x0000ffff, ++ 0x0000ffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_BFD_RELOC_8, ++ 0, ++ 0, /* byte */ ++ 8, ++ FALSE, ++ 0, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_BFD_RELOC8", ++ FALSE, ++ 0x000000ff, ++ 0x000000ff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GPREL, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_gprel_relocate, ++ "R_NIOS2_GPREL", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GNU_VTINHERIT, ++ 0, ++ 2, /* short */ ++ 0, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ NULL, ++ "R_NIOS2_GNU_VTINHERIT", ++ FALSE, ++ 0, ++ 0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GNU_VTENTRY, ++ 0, ++ 2, /* byte */ ++ 0, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ _bfd_elf_rel_vtable_reloc_fn, ++ "R_NIOS2_GNU_VTENTRY", ++ FALSE, ++ 0, ++ 0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_UJMP, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_ujmp_relocate, ++ "R_NIOS2_UJMP", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_CJMP, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_cjmp_relocate, ++ "R_NIOS2_CJMP", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_CALLR, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_callr_relocate, ++ "R_NIOS2_CALLR", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_ALIGN, ++ 0, ++ 2, ++ 0, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ nios2_elf32_ignore_reloc, ++ "R_NIOS2_ALIGN", ++ FALSE, ++ 0, ++ 0, ++ TRUE), ++ ++ ++ HOWTO (R_NIOS2_GOT16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_GOT16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_CALL16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_CALL16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GOTOFF_LO, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_GOTOFF_LO", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GOTOFF_HA, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_GOTOFF_HA", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_PCREL_LO, ++ 0, ++ 2, ++ 16, ++ TRUE, ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_pcrel_lo16_relocate, ++ "R_NIOS2_PCREL_LO", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ TRUE), ++ ++ HOWTO (R_NIOS2_PCREL_HA, ++ 0, ++ 2, ++ 16, ++ FALSE, /* This is a PC-relative relocation, but we need to subtract ++ PC ourselves before the HIADJ. */ ++ 6, ++ complain_overflow_dont, ++ nios2_elf32_pcrel_hiadj16_relocate, ++ "R_NIOS2_PCREL_HA", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ TRUE), ++ ++ HOWTO (R_NIOS2_TLS_GD16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_GD16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_LDM16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_LDM16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_LDO16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_LDO16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_IE16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_IE16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_LE16, ++ 0, ++ 2, ++ 16, ++ FALSE, ++ 6, ++ complain_overflow_bitfield, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_LE16", ++ FALSE, ++ 0x003fffc0, ++ 0x003fffc0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_DTPMOD, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_DTPMOD", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_DTPREL, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_DTPREL", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_TLS_TPREL, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_TLS_TPREL", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_COPY, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_COPY", ++ FALSE, ++ 0, ++ 0, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GLOB_DAT, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_GLOB_DAT", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_JUMP_SLOT, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_JUMP_SLOT", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_RELATIVE, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_RELATIVE", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++ HOWTO (R_NIOS2_GOTOFF, ++ 0, ++ 2, ++ 32, ++ FALSE, ++ 0, ++ complain_overflow_dont, ++ bfd_elf_generic_reloc, ++ "R_NIOS2_GOTOFF", ++ FALSE, ++ 0xffffffff, ++ 0xffffffff, ++ FALSE), ++ ++/* Add other relocations here. */ ++}; ++ ++static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; ++ ++static reloc_howto_type * ++lookup_howto (unsigned int rtype) ++{ ++ static int initialized = 0; ++ int i; ++ int howto_tbl_size = (int) (sizeof (elf_nios2_howto_table_rel) ++ / sizeof (elf_nios2_howto_table_rel[0])); ++ ++ if (!initialized) ++ { ++ initialized = 1; ++ memset (elf_code_to_howto_index, 0xff, ++ sizeof (elf_code_to_howto_index)); ++ for (i = 0; i < howto_tbl_size; i++) ++ elf_code_to_howto_index[elf_nios2_howto_table_rel[i].type] = i; ++ } ++ ++ BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL); ++ i = elf_code_to_howto_index[rtype]; ++ if (i >= howto_tbl_size) ++ return 0; ++ return elf_nios2_howto_table_rel + i; ++} ++ ++/* Map for converting BFD reloc types to New Jersey reloc types. */ ++struct elf_reloc_map ++{ ++ bfd_reloc_code_real_type bfd_val; ++ enum elf_nios2_reloc_type elf_val; ++}; ++ ++static const struct elf_reloc_map nios2_reloc_map[] = { ++ {BFD_RELOC_NIOS2_S16, R_NIOS2_S16}, ++ {BFD_RELOC_NIOS2_U16, R_NIOS2_U16}, ++ {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16}, ++ {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26}, ++ {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5}, ++ {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX}, ++ {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6}, ++ {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8}, ++ {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16}, ++ {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16}, ++ {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16}, ++ {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32}, ++ {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16}, ++ {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8}, ++ {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL}, ++ {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT}, ++ {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY}, ++ {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP}, ++ {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP}, ++ {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR}, ++ {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN}, ++ {BFD_RELOC_NIOS2_GOT16, R_NIOS2_GOT16}, ++ {BFD_RELOC_NIOS2_CALL16, R_NIOS2_CALL16}, ++ {BFD_RELOC_NIOS2_GOTOFF_LO, R_NIOS2_GOTOFF_LO}, ++ {BFD_RELOC_NIOS2_GOTOFF_HA, R_NIOS2_GOTOFF_HA}, ++ {BFD_RELOC_NIOS2_PCREL_LO, R_NIOS2_PCREL_LO}, ++ {BFD_RELOC_NIOS2_PCREL_HA, R_NIOS2_PCREL_HA}, ++ {BFD_RELOC_NIOS2_TLS_GD16, R_NIOS2_TLS_GD16}, ++ {BFD_RELOC_NIOS2_TLS_LDM16, R_NIOS2_TLS_LDM16}, ++ {BFD_RELOC_NIOS2_TLS_LDO16, R_NIOS2_TLS_LDO16}, ++ {BFD_RELOC_NIOS2_TLS_IE16, R_NIOS2_TLS_IE16}, ++ {BFD_RELOC_NIOS2_TLS_LE16, R_NIOS2_TLS_LE16}, ++ {BFD_RELOC_NIOS2_TLS_DTPMOD, R_NIOS2_TLS_DTPMOD}, ++ {BFD_RELOC_NIOS2_TLS_DTPREL, R_NIOS2_TLS_DTPREL}, ++ {BFD_RELOC_NIOS2_TLS_TPREL, R_NIOS2_TLS_TPREL}, ++ {BFD_RELOC_NIOS2_COPY, R_NIOS2_COPY}, ++ {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT}, ++ {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT}, ++ {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE}, ++ {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF} ++}; ++ ++/* The Nios II linker needs to keep track of the number of relocs that it ++ decides to copy as dynamic relocs in check_relocs for each symbol. ++ This is so that it can later discard them if they are found to be ++ unnecessary. We store the information in a field extending the ++ regular ELF linker hash table. */ ++ ++struct elf32_nios2_dyn_relocs ++{ ++ struct elf32_nios2_dyn_relocs *next; ++ ++ /* The input section of the reloc. */ ++ asection *sec; ++ ++ /* Total number of relocs copied for the input section. */ ++ bfd_size_type count; ++ ++ /* Number of pc-relative relocs copied for the input section. */ ++ bfd_size_type pc_count; ++}; ++ ++/* Nios II ELF linker hash entry. */ ++ ++struct elf32_nios2_link_hash_entry ++{ ++ struct elf_link_hash_entry root; ++ ++ /* Track dynamic relocs copied for this symbol. */ ++ struct elf32_nios2_dyn_relocs *dyn_relocs; ++ ++#define GOT_UNKNOWN 0 ++#define GOT_NORMAL 1 ++#define GOT_TLS_GD 2 ++#define GOT_TLS_IE 4 ++ unsigned char tls_type; ++ ++ /* We need to detect and take special action for symbols which are only ++ referenced with %call() and not with %got(). Such symbols do not need ++ a dynamic GOT reloc in shared objects, only a dynamic PLT reloc. Lazy ++ linking will not work if the dynamic GOT reloc exists. ++ To check for this condition efficiently, we compare got_types_used against ++ CALL16_USED, meaning ++ (got_types_used & (GOT16_USED | CALL16_USED)) == CALL16_USED. */ ++#define GOT16_USED 1 ++#define CALL16_USED 2 ++ unsigned char got_types_used; ++}; ++ ++#define elf32_nios2_hash_entry(ent) \ ++ ((struct elf32_nios2_link_hash_entry *) (ent)) ++ ++/* Get the Nios II elf linker hash table from a link_info structure. */ ++#define elf32_nios2_hash_table(info) \ ++ ((struct elf32_nios2_link_hash_table *) ((info)->hash)) ++ ++/* Nios II ELF linker hash table. */ ++struct elf32_nios2_link_hash_table ++ { ++ /* The main hash table. */ ++ struct elf_link_hash_table root; ++ ++ /* Short-cuts to get to dynamic linker sections. */ ++ asection *sgot; ++ asection *sgotplt; ++ asection *srelgot; ++ asection *splt; ++ asection *srelplt; ++ asection *sdynbss; ++ asection *srelbss; ++ asection *sbss; ++ ++ union { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ } tls_ldm_got; ++ ++ /* Small local sym to section mapping cache. */ ++ struct sym_cache sym_sec; ++ ++ bfd_vma res_n_size; ++ }; ++ ++struct nios2_elf32_obj_tdata ++{ ++ struct elf_obj_tdata root; ++ ++ /* tls_type for each local got entry. */ ++ char *local_got_tls_type; ++ ++ /* TRUE if TLS GD relocs have been seen for this object. */ ++ bfd_boolean has_tlsgd; ++}; ++ ++#define elf32_nios2_tdata(abfd) \ ++ ((struct nios2_elf32_obj_tdata *) (abfd)->tdata.any) ++ ++#define elf32_nios2_local_got_tls_type(abfd) \ ++ (elf32_nios2_tdata (abfd)->local_got_tls_type) ++ ++#define is_nios2_elf(bfd) \ ++ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ ++ && elf_object_id (bfd) == NIOS2_ELF_TDATA) ++/* 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 */ ++}; ++ ++/* Support for core dump NOTE sections */ ++static bfd_boolean ++nios2_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) ++{ ++ int offset; ++ size_t size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 212: /* Linux/Nios II */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ size = 136; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ size, note->descpos + offset); ++} ++ ++static bfd_boolean ++nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) ++{ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 124: /* Linux/Nios II elf_prpsinfo */ ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return TRUE; ++} ++ ++/* Create an entry in a Nios II ELF linker hash table. */ ++ ++static struct bfd_hash_entry * ++link_hash_newfunc (struct bfd_hash_entry *entry, ++ struct bfd_hash_table *table, const char *string) ++{ ++ /* Allocate the structure if it has not already been allocated by a ++ subclass. */ ++ if (entry == NULL) ++ { ++ entry = bfd_hash_allocate (table, ++ sizeof (struct elf32_nios2_link_hash_entry)); ++ if (entry == NULL) ++ return entry; ++ } ++ ++ /* Call the allocation method of the superclass. */ ++ entry = _bfd_elf_link_hash_newfunc (entry, table, string); ++ if (entry != NULL) ++ { ++ struct elf32_nios2_link_hash_entry *eh; ++ ++ eh = (struct elf32_nios2_link_hash_entry *) entry; ++ eh->dyn_relocs = NULL; ++ eh->tls_type = GOT_UNKNOWN; ++ eh->got_types_used = 0; ++ } ++ ++ return entry; ++} ++ ++/* Given a BFD reloc type, return a howto structure. */ ++ ++static reloc_howto_type * ++nios2_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, ++ bfd_reloc_code_real_type code) ++{ ++ int i; ++ for (i = 0; ++ i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map)); ++ ++i) ++ { ++ if (nios2_reloc_map[i].bfd_val == code) ++ return &elf_nios2_howto_table_rel[(int) nios2_reloc_map[i].elf_val]; ++ } ++ ++ return NULL; ++} ++ ++/* Given a reloc name, return a howto structure. */ ++ ++static reloc_howto_type * ++nios2_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, ++ const char *r_name) ++{ ++ unsigned int i; ++ for (i = 0; ++ i < (sizeof (elf_nios2_howto_table_rel) ++ / sizeof (elf_nios2_howto_table_rel[0])); ++ i++) ++ if (elf_nios2_howto_table_rel[i].name != NULL ++ && strcasecmp (elf_nios2_howto_table_rel[i].name, r_name) == 0) ++ return &elf_nios2_howto_table_rel[i]; ++ ++ return NULL; ++} ++ ++/* Helper function for nios2_elf32_info_to_howto. */ ++ ++static reloc_howto_type * ++nios2_elf32_rtype_to_howto (unsigned int r_type, ++ bfd_boolean rela_p ATTRIBUTE_UNUSED) ++{ ++ BFD_ASSERT (r_type < R_NIOS2_ILLEGAL); ++ return &elf_nios2_howto_table_rel[r_type]; ++} ++ ++/* Given a ELF32 relocation, fill in a arelent structure. */ ++ ++static void ++nios2_elf32_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * cache_ptr, ++ Elf_Internal_Rela * dst) ++{ ++ unsigned int r_type; ++ ++ r_type = ELF32_R_TYPE (dst->r_info); ++ cache_ptr->howto = nios2_elf32_rtype_to_howto (r_type, FALSE); ++ ++ /* FIXME - do we need to do anything else here??? */ ++} ++ ++/* 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; ++} ++ ++/* The assembler has output long jmp/call sequences for all calls ++ and pc-relative branches that it cannot guarantee are within ++ range, so the linker must attempt to "relax" these sequences to ++ short branches and calls if it can. We avoid having to re-relax by ++ replacing redundant instructions with nops instead of deleting them. */ ++static bfd_boolean ++nios2_elf32_relax_section (bfd * abfd, ++ asection * sec, ++ struct bfd_link_info *link_info, bfd_boolean * again) ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ Elf_Internal_Rela *internal_relocs; ++ Elf_Internal_Rela *irel, *irelend; ++ bfd_byte *contents = NULL; ++ Elf_Internal_Sym *isymbuf = NULL; ++ ++#define OP_MATCH_NOP 0x0001883a ++ ++ /* Assume nothing changes. */ ++ *again = FALSE; ++ ++ /* We don't have to do anything for a relocatable link, if ++ this section does not have relocs, or if this is not a ++ code section. */ ++ if (link_info->relocatable ++ || (sec->flags & SEC_RELOC) == 0 ++ || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) ++ return TRUE; ++ ++ /* If this is the first time we have been called for this section, ++ initialize the cooked size. */ ++ if (sec->size == 0) ++ sec->size = sec->rawsize; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = (_bfd_elf_link_read_relocs ++ (abfd, sec, (void *) NULL, (Elf_Internal_Rela *) NULL, ++ link_info->keep_memory)); ++ if (internal_relocs == NULL) ++ goto error_return; ++ ++ /* Walk through them looking for relaxing opportunities. */ ++ irelend = internal_relocs + sec->reloc_count; ++ for (irel = internal_relocs; irel < irelend; irel++) ++ { ++ bfd_vma symval; ++ ++ /* If this isn't something that can be relaxed, then ignore ++ this reloc. */ ++ if (ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_UJMP ++ && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CJMP ++ && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CALLR) ++ { ++ continue; ++ } ++ ++ /* Get the section contents if we haven't done so already. */ ++ if (contents == NULL) ++ { ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (sec)->this_hdr.contents != NULL) ++ contents = elf_section_data (sec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (sec->rawsize); ++ if (contents == NULL) ++ goto error_return; ++ ++ if (!bfd_get_section_contents (abfd, sec, contents, ++ (file_ptr) 0, sec->rawsize)) ++ goto error_return; ++ } ++ } ++ ++ /* Read this BFD's local symbols if we haven't done so already. */ ++ if (isymbuf == NULL && symtab_hdr->sh_info != 0) ++ { ++ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; ++ if (isymbuf == NULL) ++ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, ++ symtab_hdr->sh_info, 0, ++ NULL, NULL, NULL); ++ if (isymbuf == NULL) ++ goto error_return; ++ } ++ ++ /* Get the value of the symbol referred to by the reloc. */ ++ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) ++ { ++ /* A local symbol. */ ++ Elf_Internal_Sym *isym; ++ asection *sym_sec; ++ ++ isym = isymbuf + ELF32_R_SYM (irel->r_info); ++ if (isym->st_shndx == SHN_UNDEF) ++ sym_sec = bfd_und_section_ptr; ++ else if (isym->st_shndx == SHN_ABS) ++ sym_sec = bfd_abs_section_ptr; ++ else if (isym->st_shndx == SHN_COMMON) ++ sym_sec = bfd_com_section_ptr; ++ else ++ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ symval = (isym->st_value ++ + sym_sec->output_section->vma + sym_sec->output_offset); ++ } ++ else ++ { ++ unsigned long indx; ++ struct elf_link_hash_entry *h; ++ ++ /* An external symbol. */ ++ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; ++ h = elf_sym_hashes (abfd)[indx]; ++ BFD_ASSERT (h != NULL); ++ if (h->root.type != bfd_link_hash_defined ++ && h->root.type != bfd_link_hash_defweak) ++ { ++ /* This appears to be a reference to an undefined ++ symbol. Just ignore it--it will be caught by the ++ regular reloc processing. */ ++ continue; ++ } ++ ++ symval = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ } ++ ++ /* For simplicity of coding, we are going to modify the section ++ contents, the section relocs, and the BFD symbol table. We ++ must tell the rest of the code not to free up this ++ information. It would be possible to instead create a table ++ of changes which have to be made, as is done in coff-mips.c; ++ that would be more work, but would require less memory when ++ the linker is run. */ ++ ++ /* try to turn : ++ * movhi at, %hi(symbol) ++ * movui at, %lo(symbol) ++ * callr at ++ * into: ++ * call symbol ++ */ ++ if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CALLR) ++ { ++ bfd_vma targ_addr = symval + irel->r_addend; ++ bfd_vma curr_addr = (sec->output_section->vma + sec->output_offset); ++ bfd_vma targ_page, curr_page; ++ targ_page = targ_addr & 0xf0000000; ++ curr_page = curr_addr & 0xf0000000; ++ ++ if (targ_page == curr_page) ++ { ++ /* change the opcode to a call */ ++ bfd_put_32 (abfd, OP_MATCH_CALL, contents + irel->r_offset); ++ /* Note that we've changed the relocs, section contents, etc. */ ++ elf_section_data (sec)->relocs = internal_relocs; ++ elf_section_data (sec)->this_hdr.contents = contents; ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ ++ /* Fix the relocation's type. */ ++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), ++ R_NIOS2_CALL26); ++ ++ /* replace next two instructions with nops */ ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); ++ } ++ } ++ ++ /* try to turn : ++ * movhi at, %hi(symbol) ++ * movui at, %lo(symbol) ++ * jmp at ++ * into: ++ * br symbol ++ */ ++ if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_UJMP) ++ { ++ bfd_vma pcrel_offset; ++ Elf_Internal_Rela *irelalign = NULL; ++ Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; ++ Elf_Internal_Rela *irelend = irel + sec->reloc_count; ++ ++ for (; irela < irelend; irela++) ++ { ++ if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN ++ && irela->r_offset > irel->r_offset + 4 ++ && 8 < (1 << irela->r_addend)) ++ { ++ irelalign = irela; ++ break; ++ } ++ } ++ ++ /* calculate the pcrelative offset from current location */ ++ pcrel_offset = symval; ++ pcrel_offset -= (sec->output_section->vma + sec->output_offset); ++ pcrel_offset += irel->r_addend; ++ ++ /* we need to compute the pcrel_offset from the next instruction */ ++ pcrel_offset -= (irel->r_offset + 4); ++ ++ /* does this value fit in 16 bits */ ++ if ((irelalign == NULL && (long) pcrel_offset <= 0x8004 ++ && (long) pcrel_offset >= -0x8000) || (irelalign != NULL ++ && (long) pcrel_offset ++ <= 0x7ffc ++ && (long) pcrel_offset ++ >= -0x8000)) ++ { ++ /* change the opcode to an unconditional branch */ ++ bfd_put_32 (abfd, OP_MATCH_BR, contents + irel->r_offset); ++ /* Note that we've changed the relocs, section contents, etc. */ ++ elf_section_data (sec)->relocs = internal_relocs; ++ elf_section_data (sec)->this_hdr.contents = contents; ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ ++ /* Fix the relocation's type. */ ++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), ++ R_NIOS2_PCREL16); ++ ++ /* replace next two instructions with nops */ ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); ++ } ++ } ++ ++ /* try to turn : ++ * b{cond} a, b skip ++ * movhi at, %hi(symbol) ++ * movui at, %lo(symbol) ++ * jmp at ++ * skip: ++ * ... ++ * into: ++ * br{opp_cond} a, b, symbol ++ */ ++ if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CJMP) ++ { ++ bfd_vma pcrel_offset; ++ Elf_Internal_Rela *irelalign = NULL; ++ Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; ++ Elf_Internal_Rela *irelend = irel + sec->reloc_count; ++ ++ for (; irela < irelend; irela++) ++ { ++ if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN ++ && irela->r_offset > irel->r_offset + 4 ++ && 8 < (1 << irela->r_addend)) ++ { ++ irelalign = irela; ++ break; ++ } ++ } ++ ++ /* calculate the pcrelative offset from current location */ ++ pcrel_offset = symval; ++ pcrel_offset -= (sec->output_section->vma + sec->output_offset); ++ pcrel_offset += irel->r_addend; ++ ++ /* we need to compute the pcrel_offset from this instruction ++ * ie the movhi */ ++ pcrel_offset -= (irel->r_offset); ++ ++ /* does this value fit in 16 bits */ ++ if ((irelalign == NULL && (long) pcrel_offset <= 0x8008 ++ && (long) pcrel_offset >= -0x8000) || (irelalign != NULL ++ && (long) pcrel_offset ++ <= 0x7ffc ++ && (long) pcrel_offset ++ >= -0x8000)) ++ { ++ unsigned long opcode, op_a, op_b; ++ /* get the conditional branch opcode */ ++ opcode = bfd_get_32 (abfd, contents + irel->r_offset - 4); ++ /* reverse the condition */ ++ switch (opcode & OP_MASK_OP) ++ { ++ case OP_MATCH_BEQ: ++ opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BNE; ++ break; ++ case OP_MATCH_BNE: ++ opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BEQ; ++ break; ++ case OP_MATCH_BGE: ++ case OP_MATCH_BGEU: ++ case OP_MATCH_BLT: ++ case OP_MATCH_BLTU: ++ /* swap the operands */ ++ op_a = (opcode & OP_MASK_RRT) << 5; ++ op_b = (opcode & OP_MASK_RRS) >> 5; ++ opcode = ++ (opcode & ~(OP_MASK_RRS | OP_MASK_RRT)) | op_a | op_b; ++ break; ++ default: ++ fprintf (stderr, ++ "relaxation error - expecting conditional branch, " ++ "aborting\n"); ++ abort (); ++ break; ++ } ++ ++ /* We must set the branch target to zero so that the skip over ++ the jmp doesn't get added to the jmp. */ ++ opcode = opcode & (~OP_MASK_IMM16); ++ ++ /* Change the opcode to the reversed conditional branch. */ ++ bfd_put_32 (abfd, opcode, contents + irel->r_offset - 4); ++ /* Note that we've changed the relocs, section contents, etc. */ ++ elf_section_data (sec)->relocs = internal_relocs; ++ elf_section_data (sec)->this_hdr.contents = contents; ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ ++ /* Fix the relocation's type. */ ++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), ++ R_NIOS2_PCREL16); ++ ++ /* This relocation's offset has also been reduced by 4 bytes. */ ++ irel->r_offset -= 4; ++ ++ /* Replace next two instructions with nops. */ ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); ++ bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 12); ++ } ++ } ++ ++ /* Otherwise, leave alone. */ ++ } ++ ++ if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) ++ { ++ if (!link_info->keep_memory) ++ free (isymbuf); ++ else ++ { ++ /* Cache the symbols for elf_link_input_bfd. */ ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ } ++ } ++ ++ if (contents != NULL ++ && elf_section_data (sec)->this_hdr.contents != contents) ++ { ++ if (!link_info->keep_memory) ++ free (contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (sec)->this_hdr.contents = contents; ++ } ++ } ++ ++ if (internal_relocs != NULL ++ && elf_section_data (sec)->relocs != internal_relocs) ++ free (internal_relocs); ++ ++ ++ return TRUE; ++ ++error_return: ++ if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) ++ free (isymbuf); ++ if (contents != NULL ++ && elf_section_data (sec)->this_hdr.contents != contents) ++ free (contents); ++ if (internal_relocs != NULL ++ && elf_section_data (sec)->relocs != internal_relocs) ++ free (internal_relocs); ++ ++ return FALSE; ++} ++#if 0 ++/* Delete some bytes from a section while relaxing. ++ * Copied from mn10200 port */ ++ ++static bfd_boolean ++nios2_elf32_relax_delete_bytes (bfd * abfd, ++ asection * sec, bfd_vma addr, int count) ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ unsigned int sec_shndx; ++ bfd_byte *contents; ++ Elf_Internal_Rela *irel, *irelend; ++ Elf_Internal_Rela *irelalign; ++ bfd_vma toaddr; ++ Elf_Internal_Sym *isym; ++ Elf_Internal_Sym *isymend; ++ struct elf_link_hash_entry **sym_hashes; ++ struct elf_link_hash_entry **end_hashes; ++ unsigned int symcount; ++ asection *asec; ++ ++ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); ++ ++ contents = elf_section_data (sec)->this_hdr.contents; ++ ++ /* The deletion must stop at the next ALIGN reloc for an aligment ++ power larger than the number of bytes we are deleting. */ ++ ++ irelalign = NULL; ++ /* +1 because we need to readjust symbols at end of section */ ++ toaddr = sec->size + 1; ++ ++ irel = elf_section_data (sec)->relocs; ++ irelend = irel + sec->reloc_count; ++ ++ for (; irel < irelend; irel++) ++ { ++ if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_ALIGN ++ && irel->r_offset > addr && count < (1 << irel->r_addend)) ++ { ++ irelalign = irel; ++ /* +1 because we need to readjust symbols at end of section */ ++ toaddr = irel->r_offset + 1; ++ break; ++ } ++ } ++ ++ ++ /* Actually delete the bytes. */ ++ memmove (contents + addr, contents + addr + count, ++ (size_t) ((toaddr - 1) - addr - count)); ++ ++ if (irelalign == NULL) ++ sec->size -= count; ++ else ++ { ++ int i; ++ ++#define NOP_OPCODE (0x0001883a) ++ ++ BFD_ASSERT ((count & 3) == 0); ++ for (i = 0; i < count; i += 4) ++ bfd_put_32 (abfd, (bfd_vma) NOP_OPCODE, ++ contents + (toaddr - 1) - count + i); ++ } ++ ++ /* get the symbol table */ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ isym = (Elf_Internal_Sym *) symtab_hdr->contents; ++ ++ /* Adjust all the reloc offsets in this section. */ ++ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) ++ { ++ /* Get the new reloc address. */ ++ if ((irel->r_offset > addr && irel->r_offset < toaddr)) ++ irel->r_offset -= count; ++ } ++ ++ /* Adjust relocations against targets in this section whose positions ++ * have moved as a result of the relaxation */ ++ ++ for (asec = abfd->sections; asec; asec = asec->next) ++ { ++ irelend = elf_section_data (asec)->relocs + asec->reloc_count; ++ for (irel = elf_section_data (asec)->relocs; irel < irelend; irel++) ++ { ++ Elf_Internal_Sym *sym; ++ /* if the symbol which this reloc is against doesn't change ++ * we need to change the reloc addend */ ++ ++ sym = isym + ELF32_R_SYM (irel->r_info); ++ if (sym->st_shndx == sec_shndx ++ && !(sym->st_value > addr && sym->st_value < toaddr) ++ && sym->st_value + irel->r_addend > addr ++ && sym->st_value + irel->r_addend < toaddr) ++ { ++ irel->r_addend -= count; ++ } ++ ++ } ++ } ++ ++ /* Adjust the local symbols defined in this section. */ ++ for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) ++ { ++ if (isym->st_shndx == sec_shndx ++ && isym->st_value > addr && isym->st_value < toaddr) ++ isym->st_value -= count; ++ ++ ++ } ++ ++ /* Now adjust the global symbols defined in this section. */ ++ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) ++ - symtab_hdr->sh_info); ++ sym_hashes = elf_sym_hashes (abfd); ++ end_hashes = sym_hashes + symcount; ++ for (; sym_hashes < end_hashes; sym_hashes++) ++ { ++ struct elf_link_hash_entry *sym_hash = *sym_hashes; ++ if ((sym_hash->root.type == bfd_link_hash_defined ++ || sym_hash->root.type == bfd_link_hash_defweak) ++ && sym_hash->root.u.def.section == sec ++ && sym_hash->root.u.def.value > addr ++ && sym_hash->root.u.def.value < toaddr) ++ { ++ sym_hash->root.u.def.value -= count; ++ } ++ } ++ ++ return TRUE; ++} ++#endif ++struct bfd_link_info *nios2_link_info = NULL; ++ ++void ++_bfd_set_link_info (struct bfd_link_info *info) ++{ ++ nios2_link_info = info; ++} ++ ++bfd_boolean linker_force_make_executable = FALSE; ++ ++void ++_bfd_set_force_make_executable (bfd_boolean force) ++{ ++ linker_force_make_executable = force; ++} ++ ++/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a ++ dangerous relocation. */ ++ ++static bfd_boolean ++nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) ++{ ++ ++ bfd_boolean gp_found; ++ struct bfd_hash_entry *h; ++ struct bfd_link_hash_entry *lh; ++ ++ /* If we've already figured out what GP will be, just return it. */ ++ *pgp = _bfd_get_gp_value (output_bfd); ++ if (*pgp) ++ return TRUE; ++ ++ h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE); ++ lh = (struct bfd_link_hash_entry *) h; ++lookup: ++ if (lh) ++ { ++ switch (lh->type) ++ { ++ case bfd_link_hash_undefined: ++ case bfd_link_hash_undefweak: ++ case bfd_link_hash_common: ++ gp_found = FALSE; ++ break; ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ gp_found = TRUE; ++ *pgp = lh->u.def.value; ++ break; ++ case bfd_link_hash_indirect: ++ case bfd_link_hash_warning: ++ lh = lh->u.i.link; ++ /* @@FIXME ignoring warning for now */ ++ goto lookup; ++ case bfd_link_hash_new: ++ default: ++ abort (); ++ } ++ } ++ else ++ gp_found = FALSE; ++ ++ if (!gp_found) ++ { ++ /* Only get the error once. */ ++ *pgp = 4; ++ _bfd_set_gp_value (output_bfd, *pgp); ++ return FALSE; ++ } ++ ++ _bfd_set_gp_value (output_bfd, *pgp); ++ ++ return TRUE; ++} ++ ++/* We have to figure out the gp value, so that we can adjust the ++ symbol value correctly. We look up the symbol _gp in the output ++ BFD. If we can't find it, we're stuck. We cache it in the ELF ++ target data. We don't need to adjust the symbol value for an ++ external symbol if we are producing relocatable output. */ ++ ++static bfd_reloc_status_type ++nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, ++ char **error_message, bfd_vma *pgp, ++ struct bfd_link_info *info) ++{ ++ 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 this is called without link_info, then ++ we cannot be doing a final link */ ++ if (info == NULL) ++ relocatable = TRUE; ++ ++ if (relocatable) ++ { ++ /* Make up a value. */ ++ *pgp = symbol->section->output_section->vma + 0x4000; ++ _bfd_set_gp_value (output_bfd, *pgp); ++ } ++ else if (!nios2_elf_assign_gp (output_bfd, pgp, info)) ++ { ++ *error_message = ++ (char *) ++ _("global pointer relative relocation when _gp not defined"); ++ return bfd_reloc_dangerous; ++ } ++ } ++ ++ return bfd_reloc_ok; ++} ++ ++ ++/* 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ relocation = symbol->value ++ + symbol->section->output_section->vma + symbol->section->output_offset; ++ ++ if ((r = ++ nios2_elf_final_gp (abfd, symbol, FALSE, msg, &gp, ++ nios2_link_info)) == 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ 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 != (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_ok; ++ ++ ++ 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); ++} ++ ++/* Do the relocations which require special handling. */ ++ ++static bfd_reloc_status_type ++nios2_elf32_do_hi16_