This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 2/9] Nios II port, bfd support


This patch adds BFD support for Nios II.

-Sandra

2013-01-24  Sandra Loosemore  <sandra@codesourcery.com>
            Andrew Jenner <andrew@codesourcery.com>

Based on patches from Altera Corporation.

	bfd/
	* Makefile.am (ALL_MACHINES): Add cpu-nios2.lo.
	(ALL_MACHINES_CFILES): Add cpu-nios2.c.
	(BFD_BACKENDS): Add elf32-nios2.lo.
	(BFD32_BACKENDS_CFILES): Add elf32-nios2.c.
	* Makefile.in: Regenerated.
	* configure.in: Add entries for bfd_elf32_bignios2_vec and
	bfd_elf32_littlenios2_vec.
	* configure: Regenerated.
	* config.bfd: Add cases for nios2.
	* archures.c (enum bfd_architecture): Add bfd_arch_nios2.
	(bfd_mach_nios2): Define.
	(bfd_nios2_arch): Declare.
	(bfd_archures_list): Add bfd_nios2_arch.
	* targets.c (bfd_elf32_bignios2_vec): Declare.
	(bfd_elf32_littlenios2_vec): Declare.
	(_bfd_target_vector): Add entries for bfd_elf32_bignios2_vec and
	bfd_elf32_littlenios2_vec.
	* elf-bfd.h (enum elf_target_id): Add NIOS2_ELF_DATA.
	* reloc.c (enum bfd_reloc_code_real): Add Nios II relocations.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Regenerated.
	* cpu-nios2.c: New file.
	* elf32-nios2.c: New file.

	include/elf
	* nios2.h: New file.
Index: bfd/Makefile.am
===================================================================
RCS file: /cvs/src/src/bfd/Makefile.am,v
retrieving revision 1.269
diff -u -p -r1.269 Makefile.am
--- bfd/Makefile.am	10 Jan 2013 09:49:04 -0000	1.269
+++ bfd/Makefile.am	22 Jan 2013 18:36:30 -0000
@@ -136,6 +136,7 @@ ALL_MACHINES = \
 	cpu-moxie.lo \
 	cpu-msp430.lo \
 	cpu-mt.lo \
+	cpu-nios2.lo \
 	cpu-ns32k.lo \
 	cpu-openrisc.lo \
 	cpu-or32.lo \
@@ -220,6 +221,7 @@ ALL_MACHINES_CFILES = \
 	cpu-msp430.c \
 	cpu-mt.c \
 	cpu-ns32k.c \
+	cpu-nios2.c \
 	cpu-openrisc.c \
 	cpu-or32.c \
 	cpu-pdp11.c \
@@ -348,6 +350,7 @@ BFD32_BACKENDS = \
 	elf32-moxie.lo \
 	elf32-msp430.lo \
 	elf32-mt.lo \
+	elf32-nios2.lo \
 	elf32-openrisc.lo \
 	elf32-or32.lo \
 	elf32-pj.lo \
@@ -537,6 +540,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-moxie.c \
 	elf32-msp430.c \
 	elf32-mt.c \
+	elf32-nios2.c \
 	elf32-openrisc.c \
 	elf32-or32.c \
 	elf32-pj.c \
Index: bfd/Makefile.in
===================================================================
RCS file: /cvs/src/src/bfd/Makefile.in,v
retrieving revision 1.299
diff -u -p -r1.299 Makefile.in
--- bfd/Makefile.in	10 Jan 2013 09:49:04 -0000	1.299
+++ bfd/Makefile.in	22 Jan 2013 18:36:30 -0000
@@ -437,6 +437,7 @@ ALL_MACHINES = \
 	cpu-moxie.lo \
 	cpu-msp430.lo \
 	cpu-mt.lo \
+	cpu-nios2.lo \
 	cpu-ns32k.lo \
 	cpu-openrisc.lo \
 	cpu-or32.lo \
@@ -521,6 +522,7 @@ ALL_MACHINES_CFILES = \
 	cpu-msp430.c \
 	cpu-mt.c \
 	cpu-ns32k.c \
+	cpu-nios2.c \
 	cpu-openrisc.c \
 	cpu-or32.c \
 	cpu-pdp11.c \
@@ -650,6 +652,7 @@ BFD32_BACKENDS = \
 	elf32-moxie.lo \
 	elf32-msp430.lo \
 	elf32-mt.lo \
+	elf32-nios2.lo \
 	elf32-openrisc.lo \
 	elf32-or32.lo \
 	elf32-pj.lo \
@@ -839,6 +842,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-moxie.c \
 	elf32-msp430.c \
 	elf32-mt.c \
+	elf32-nios2.c \
 	elf32-openrisc.c \
 	elf32-or32.c \
 	elf32-pj.c \
@@ -1347,6 +1351,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-moxie.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-msp430.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nios2.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ns32k.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-openrisc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-or32.Plo@am__quote@
@@ -1435,6 +1440,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nios2.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-openrisc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or32.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@
Index: bfd/configure.in
===================================================================
RCS file: /cvs/src/src/bfd/configure.in,v
retrieving revision 1.327
diff -u -p -r1.327 configure.in
--- bfd/configure.in	10 Jan 2013 09:49:08 -0000	1.327
+++ bfd/configure.in	22 Jan 2013 18:36:31 -0000
@@ -725,6 +725,7 @@ do
     bfd_elf32_bigmips_vxworks_vec)
 			 	tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
     bfd_elf32_bigmoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;;
+    bfd_elf32_bignios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;;
     bfd_elf32_cr16_vec)		tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
     bfd_elf32_cr16c_vec)	tb="$tb elf32-cr16c.lo elf32.lo $elf" ;;
     bfd_elf32_cris_vec)		tb="$tb elf32-cris.lo elf32.lo $elf" ;;
@@ -767,6 +768,7 @@ do
     bfd_elf32_littlemips_vxworks_vec)
 			 	tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
     bfd_elf32_littlemoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;;
+    bfd_elf32_littlenios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;;
     bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;;
     bfd_elf32_m32r_vec)		tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
     bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
Index: bfd/configure
===================================================================
RCS file: /cvs/src/src/bfd/configure,v
retrieving revision 1.379
diff -u -p -r1.379 configure
--- bfd/configure	10 Jan 2013 09:49:05 -0000	1.379
+++ bfd/configure	22 Jan 2013 18:36:31 -0000
@@ -15228,6 +15228,7 @@ do
     bfd_elf32_bigmips_vxworks_vec)
 			 	tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
     bfd_elf32_bigmoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;;
+    bfd_elf32_bignios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;;
     bfd_elf32_cr16_vec)		tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
     bfd_elf32_cr16c_vec)	tb="$tb elf32-cr16c.lo elf32.lo $elf" ;;
     bfd_elf32_cris_vec)		tb="$tb elf32-cris.lo elf32.lo $elf" ;;
@@ -15270,6 +15271,7 @@ do
     bfd_elf32_littlemips_vxworks_vec)
 			 	tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
     bfd_elf32_littlemoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;;
+    bfd_elf32_littlenios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;;
     bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;;
     bfd_elf32_m32r_vec)		tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
     bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
Index: bfd/config.bfd
===================================================================
RCS file: /cvs/src/src/bfd/config.bfd,v
retrieving revision 1.305
diff -u -p -r1.305 config.bfd
--- bfd/config.bfd	10 Jan 2013 09:49:05 -0000	1.305
+++ bfd/config.bfd	22 Jan 2013 18:36:31 -0000
@@ -109,6 +109,7 @@ m68*)		 targ_archs=bfd_m68k_arch ;;
 m88*)		 targ_archs=bfd_m88k_arch ;;
 microblaze*)	 targ_archs=bfd_microblaze_arch ;;
 mips*)		 targ_archs=bfd_mips_arch ;;
+nios2*)          targ_archs=bfd_nios2_arch ;;
 or32*)		 targ_archs=bfd_or32_arch ;;
 pdp11*)		 targ_archs=bfd_pdp11_arch ;;
 pj*)		 targ_archs="bfd_pj_arch bfd_i386_arch";;
@@ -1145,6 +1146,21 @@ case "${targ}" in
     targ_underscore=yes
     ;;
 
+  nios2eb-*-*)
+    targ_defvec=bfd_elf32_bignios2_vec
+    targ_selvecs=bfd_elf32_littlenios2_vec
+    ;;
+
+  nios2el-*-*)
+    targ_defvec=bfd_elf32_littlenios2_vec
+    targ_selvecs=bfd_elf32_bignios2_vec
+    ;;
+
+  nios2-*-*)
+    targ_defvec=bfd_elf32_littlenios2_vec
+    targ_selvecs=bfd_elf32_bignios2_vec
+    ;;
+
   openrisc-*-elf)
     targ_defvec=bfd_elf32_openrisc_vec
     ;;
Index: bfd/archures.c
===================================================================
RCS file: /cvs/src/src/bfd/archures.c,v
retrieving revision 1.173
diff -u -p -r1.173 archures.c
--- bfd/archures.c	10 Jan 2013 20:03:52 -0000	1.173
+++ bfd/archures.c	22 Jan 2013 18:36:30 -0000
@@ -467,6 +467,8 @@ DESCRIPTION
 .#define bfd_mach_tilegx32  2
 .  bfd_arch_aarch64,   {* AArch64  *}
 .#define bfd_mach_aarch64 0
+.  bfd_arch_nios2,
+.#define bfd_mach_nios2	0
 .  bfd_arch_last
 .  };
 */
@@ -559,6 +561,7 @@ extern const bfd_arch_info_type bfd_mn10
 extern const bfd_arch_info_type bfd_moxie_arch;
 extern const bfd_arch_info_type bfd_msp430_arch;
 extern const bfd_arch_info_type bfd_mt_arch;
+extern const bfd_arch_info_type bfd_nios2_arch;
 extern const bfd_arch_info_type bfd_ns32k_arch;
 extern const bfd_arch_info_type bfd_openrisc_arch;
 extern const bfd_arch_info_type bfd_or32_arch;
@@ -647,6 +650,7 @@ static const bfd_arch_info_type * const 
     &bfd_moxie_arch,
     &bfd_msp430_arch,
     &bfd_mt_arch,
+    &bfd_nios2_arch,
     &bfd_ns32k_arch,
     &bfd_openrisc_arch,
     &bfd_or32_arch,
Index: bfd/targets.c
===================================================================
RCS file: /cvs/src/src/bfd/targets.c,v
retrieving revision 1.222
diff -u -p -r1.222 targets.c
--- bfd/targets.c	10 Jan 2013 09:49:08 -0000	1.222
+++ bfd/targets.c	22 Jan 2013 18:36:34 -0000
@@ -607,6 +607,7 @@ extern const bfd_target bfd_elf32_bigarm
 extern const bfd_target bfd_elf32_bigmips_vec;
 extern const bfd_target bfd_elf32_bigmips_vxworks_vec;
 extern const bfd_target bfd_elf32_bigmoxie_vec;
+extern const bfd_target bfd_elf32_bignios2_vec;
 extern const bfd_target bfd_elf32_cr16_vec;
 extern const bfd_target bfd_elf32_cr16c_vec;
 extern const bfd_target bfd_elf32_cris_vec;
@@ -646,6 +647,7 @@ extern const bfd_target bfd_elf32_little
 extern const bfd_target bfd_elf32_littlemips_vec;
 extern const bfd_target bfd_elf32_littlemips_vxworks_vec;
 extern const bfd_target bfd_elf32_littlemoxie_vec;
+extern const bfd_target bfd_elf32_littlenios2_vec;
 extern const bfd_target bfd_elf32_m32c_vec;
 extern const bfd_target bfd_elf32_m32r_vec;
 extern const bfd_target bfd_elf32_m32rle_vec;
@@ -984,6 +986,7 @@ static const bfd_target * const _bfd_tar
 	&bfd_elf32_bigmips_vec,
 	&bfd_elf32_bigmips_vxworks_vec,
  	&bfd_elf32_bigmoxie_vec,
+ 	&bfd_elf32_bignios2_vec,
 	&bfd_elf32_cr16_vec,
 	&bfd_elf32_cr16c_vec,
 	&bfd_elf32_cris_vec,
@@ -1025,6 +1028,7 @@ static const bfd_target * const _bfd_tar
 	&bfd_elf32_littlemips_vec,
 	&bfd_elf32_littlemips_vxworks_vec,
  	&bfd_elf32_littlemoxie_vec,
+ 	&bfd_elf32_littlenios2_vec,
 	&bfd_elf32_m32c_vec,
 	&bfd_elf32_m32r_vec,
         &bfd_elf32_m32rle_vec,
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.355
diff -u -p -r1.355 elf-bfd.h
--- bfd/elf-bfd.h	13 Jan 2013 12:32:10 -0000	1.355
+++ bfd/elf-bfd.h	22 Jan 2013 18:36:31 -0000
@@ -421,6 +421,7 @@ enum elf_target_id
   MICROBLAZE_ELF_DATA,
   MIPS_ELF_DATA,
   MN10300_ELF_DATA,
+  NIOS2_ELF_DATA,
   PPC32_ELF_DATA,
   PPC64_ELF_DATA,
   S390_ELF_DATA,
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.241
diff -u -p -r1.241 reloc.c
--- bfd/reloc.c	16 Jan 2013 21:34:46 -0000	1.241
+++ bfd/reloc.c	22 Jan 2013 18:36:33 -0000
@@ -5665,6 +5665,77 @@ ENUMDOC
   msp430 specific relocation codes
 
 ENUM
+  BFD_RELOC_NIOS2_S16
+ENUMX
+  BFD_RELOC_NIOS2_U16
+ENUMX
+  BFD_RELOC_NIOS2_CALL26
+ENUMX
+  BFD_RELOC_NIOS2_IMM5
+ENUMX
+  BFD_RELOC_NIOS2_CACHE_OPX
+ENUMX
+  BFD_RELOC_NIOS2_IMM6
+ENUMX
+  BFD_RELOC_NIOS2_IMM8
+ENUMX
+  BFD_RELOC_NIOS2_HI16
+ENUMX
+  BFD_RELOC_NIOS2_LO16
+ENUMX
+  BFD_RELOC_NIOS2_HIADJ16
+ENUMX
+  BFD_RELOC_NIOS2_GPREL
+ENUMX 
+  BFD_RELOC_NIOS2_UJMP
+ENUMX
+  BFD_RELOC_NIOS2_CJMP
+ENUMX
+  BFD_RELOC_NIOS2_CALLR
+ENUMX
+  BFD_RELOC_NIOS2_ALIGN
+ENUMX
+  BFD_RELOC_NIOS2_GOT16
+ENUMX
+  BFD_RELOC_NIOS2_CALL16
+ENUMX
+  BFD_RELOC_NIOS2_GOTOFF_LO
+ENUMX
+  BFD_RELOC_NIOS2_GOTOFF_HA
+ENUMX
+  BFD_RELOC_NIOS2_PCREL_LO
+ENUMX
+  BFD_RELOC_NIOS2_PCREL_HA
+ENUMX
+  BFD_RELOC_NIOS2_TLS_GD16
+ENUMX
+  BFD_RELOC_NIOS2_TLS_LDM16
+ENUMX
+  BFD_RELOC_NIOS2_TLS_LDO16
+ENUMX
+  BFD_RELOC_NIOS2_TLS_IE16
+ENUMX
+  BFD_RELOC_NIOS2_TLS_LE16
+ENUMX
+  BFD_RELOC_NIOS2_TLS_DTPMOD
+ENUMX
+  BFD_RELOC_NIOS2_TLS_DTPREL
+ENUMX
+  BFD_RELOC_NIOS2_TLS_TPREL
+ENUMX
+  BFD_RELOC_NIOS2_COPY
+ENUMX
+  BFD_RELOC_NIOS2_GLOB_DAT
+ENUMX
+  BFD_RELOC_NIOS2_JUMP_SLOT
+ENUMX
+  BFD_RELOC_NIOS2_RELATIVE
+ENUMX
+  BFD_RELOC_NIOS2_GOTOFF
+ENUMDOC
+  Relocations used by the Altera Nios II core.
+
+ENUM
   BFD_RELOC_IQ2000_OFFSET_16
 ENUMX
   BFD_RELOC_IQ2000_OFFSET_21
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.595
diff -u -p -r1.595 bfd-in2.h
--- bfd/bfd-in2.h	16 Jan 2013 21:34:45 -0000	1.595
+++ bfd/bfd-in2.h	22 Jan 2013 18:36:30 -0000
@@ -2198,6 +2198,8 @@ enum bfd_architecture
 #define bfd_mach_tilegx32  2
   bfd_arch_aarch64,   /* AArch64  */
 #define bfd_mach_aarch64 0
+  bfd_arch_nios2,
+#define bfd_mach_nios2 0
   bfd_arch_last
   };
 
@@ -4912,6 +4914,42 @@ a matching LO8XG part.  */
   BFD_RELOC_MSP430_2X_PCREL,
   BFD_RELOC_MSP430_RL_PCREL,
 
+/* Relocations used by the Altera Nios II core.  */
+  BFD_RELOC_NIOS2_S16,
+  BFD_RELOC_NIOS2_U16,
+  BFD_RELOC_NIOS2_CALL26,
+  BFD_RELOC_NIOS2_IMM5,
+  BFD_RELOC_NIOS2_CACHE_OPX,
+  BFD_RELOC_NIOS2_IMM6,
+  BFD_RELOC_NIOS2_IMM8,
+  BFD_RELOC_NIOS2_HI16,
+  BFD_RELOC_NIOS2_LO16,
+  BFD_RELOC_NIOS2_HIADJ16,
+  BFD_RELOC_NIOS2_GPREL,
+  BFD_RELOC_NIOS2_UJMP,
+  BFD_RELOC_NIOS2_CJMP,
+  BFD_RELOC_NIOS2_CALLR,
+  BFD_RELOC_NIOS2_ALIGN,
+  BFD_RELOC_NIOS2_GOT16,
+  BFD_RELOC_NIOS2_CALL16,
+  BFD_RELOC_NIOS2_GOTOFF_LO,
+  BFD_RELOC_NIOS2_GOTOFF_HA,
+  BFD_RELOC_NIOS2_PCREL_LO,
+  BFD_RELOC_NIOS2_PCREL_HA,
+  BFD_RELOC_NIOS2_TLS_GD16,
+  BFD_RELOC_NIOS2_TLS_LDM16,
+  BFD_RELOC_NIOS2_TLS_LDO16,
+  BFD_RELOC_NIOS2_TLS_IE16,
+  BFD_RELOC_NIOS2_TLS_LE16,
+  BFD_RELOC_NIOS2_TLS_DTPMOD,
+  BFD_RELOC_NIOS2_TLS_DTPREL,
+  BFD_RELOC_NIOS2_TLS_TPREL,
+  BFD_RELOC_NIOS2_COPY,
+  BFD_RELOC_NIOS2_GLOB_DAT,
+  BFD_RELOC_NIOS2_JUMP_SLOT,
+  BFD_RELOC_NIOS2_RELATIVE,
+  BFD_RELOC_NIOS2_GOTOFF,
+
 /* IQ2000 Relocations.  */
   BFD_RELOC_IQ2000_OFFSET_16,
   BFD_RELOC_IQ2000_OFFSET_21,
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.290
diff -u -p -r1.290 libbfd.h
--- bfd/libbfd.h	16 Jan 2013 21:34:46 -0000	1.290
+++ bfd/libbfd.h	22 Jan 2013 18:36:33 -0000
@@ -2370,6 +2370,40 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_MSP430_16_BYTE",
   "BFD_RELOC_MSP430_2X_PCREL",
   "BFD_RELOC_MSP430_RL_PCREL",
+  "BFD_RELOC_NIOS2_S16",
+  "BFD_RELOC_NIOS2_U16",
+  "BFD_RELOC_NIOS2_CALL26",
+  "BFD_RELOC_NIOS2_IMM5",
+  "BFD_RELOC_NIOS2_CACHE_OPX",
+  "BFD_RELOC_NIOS2_IMM6",
+  "BFD_RELOC_NIOS2_IMM8",
+  "BFD_RELOC_NIOS2_HI16",
+  "BFD_RELOC_NIOS2_LO16",
+  "BFD_RELOC_NIOS2_HIADJ16",
+  "BFD_RELOC_NIOS2_GPREL",
+  "BFD_RELOC_NIOS2_UJMP",
+  "BFD_RELOC_NIOS2_CJMP",
+  "BFD_RELOC_NIOS2_CALLR",
+  "BFD_RELOC_NIOS2_ALIGN",
+  "BFD_RELOC_NIOS2_GOT16",
+  "BFD_RELOC_NIOS2_CALL16",
+  "BFD_RELOC_NIOS2_GOTOFF_LO",
+  "BFD_RELOC_NIOS2_GOTOFF_HA",
+  "BFD_RELOC_NIOS2_PCREL_LO",
+  "BFD_RELOC_NIOS2_PCREL_HA",
+  "BFD_RELOC_NIOS2_TLS_GD16",
+  "BFD_RELOC_NIOS2_TLS_LDM16",
+  "BFD_RELOC_NIOS2_TLS_LDO16",
+  "BFD_RELOC_NIOS2_TLS_IE16",
+  "BFD_RELOC_NIOS2_TLS_LE16",
+  "BFD_RELOC_NIOS2_TLS_DTPMOD",
+  "BFD_RELOC_NIOS2_TLS_DTPREL",
+  "BFD_RELOC_NIOS2_TLS_TPREL",
+  "BFD_RELOC_NIOS2_COPY",
+  "BFD_RELOC_NIOS2_GLOB_DAT",
+  "BFD_RELOC_NIOS2_JUMP_SLOT",
+  "BFD_RELOC_NIOS2_RELATIVE",
+  "BFD_RELOC_NIOS2_GOTOFF",
   "BFD_RELOC_IQ2000_OFFSET_16",
   "BFD_RELOC_IQ2000_OFFSET_21",
   "BFD_RELOC_IQ2000_UHI16",
Index: bfd/cpu-nios2.c
===================================================================
RCS file: bfd/cpu-nios2.c
diff -N bfd/cpu-nios2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bfd/cpu-nios2.c	22 Jan 2013 18:36:31 -0000
@@ -0,0 +1,44 @@
+/* BFD support for the Altera Nios II processor.
+   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Contributed by Nigel Gray (ngray@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT)		\
+  {							\
+    BITS_WORD, /*  bits in a word */			\
+    BITS_ADDR, /* bits in an address */			\
+    8,	/* 8 bits in a byte */				\
+    bfd_arch_nios2,					\
+    NUMBER,						\
+    "nios2",						\
+    PRINT,						\
+    3,							\
+    DEFAULT,						\
+    bfd_default_compatible,				\
+    bfd_default_scan,					\
+    bfd_arch_default_fill,			       	\
+    NEXT						\
+  }
+
+const bfd_arch_info_type bfd_nios2_arch = N (32, 32, 0, "nios2", TRUE, NULL);
Index: bfd/elf32-nios2.c
===================================================================
RCS file: bfd/elf32-nios2.c
diff -N bfd/elf32-nios2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ bfd/elf32-nios2.c	22 Jan 2013 18:36:32 -0000
@@ -0,0 +1,4182 @@
+/* 32-bit ELF support for Nios II.
+   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Contributed by Nigel Gray (ngray@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* This file handles Altera Nios II ELF targets  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "bfdlink.h"
+#include "genlink.h"
+#include "elf-bfd.h"
+#include "elf/nios2.h"
+#include "opcode/nios2.h"
+
+/* Use RELA relocations.  */
+#ifndef USE_RELA
+#define USE_RELA
+#endif
+
+#ifdef USE_REL
+#undef USE_REL
+#endif
+
+/* Forward declarations.  */
+static bfd_reloc_status_type nios2_elf32_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_hi16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_lo16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_hiadj16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_pcrel_lo16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_pcrel_hiadj16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_pcrel16_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_call26_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_gprel_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_ujmp_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_cjmp_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type nios2_elf32_callr_relocate
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+
+/* Target vector.  */
+extern const bfd_target bfd_elf32_littlenios2_vec;
+extern const bfd_target bfd_elf32_bignios2_vec;
+
+/* Offset of tp and dtp pointers from start of TLS block.  */
+#define TP_OFFSET       0x7000
+#define DTP_OFFSET      0x8000
+
+/* The relocation table used for SHT_REL sections.  */
+static reloc_howto_type elf_nios2_howto_table_rel[] = {
+  /* No relocation.  */
+  HOWTO (R_NIOS2_NONE,		/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_NIOS2_NONE",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* 16-bit signed immediate relocation.  */
+  HOWTO (R_NIOS2_S16,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 6,			/* bitpos */
+	 complain_overflow_signed,	/* complain on overflow */
+	 bfd_elf_generic_reloc,	/* special function */
+	 "R_NIOS2_S16",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0x003fffc0,		/* src_mask */
+	 0x003fffc0,		/* dest_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* 16-bit unsigned immediate relocation.  */
+  HOWTO (R_NIOS2_U16,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 6,			/* bitpos */
+	 complain_overflow_unsigned,	/* complain on overflow */
+	 bfd_elf_generic_reloc,	/* special function */
+	 "R_NIOS2_U16",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0x003fffc0,		/* src_mask */
+	 0x003fffc0,		/* dest_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_NIOS2_PCREL16,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 6,			/* bitpos */
+	 complain_overflow_signed,	/* complain on overflow */
+	 nios2_elf32_pcrel16_relocate,	/* special function */
+	 "R_NIOS2_PCREL16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x003fffc0,		/* src_mask */
+	 0x003fffc0,		/* dest_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_NIOS2_CALL26,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 6,			/* bitpos */
+	 complain_overflow_dont,	/* complain on overflow */
+	 nios2_elf32_call26_relocate,	/* special function */
+	 "R_NIOS2_CALL26",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffc0,		/* src_mask */
+	 0xffffffc0,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_NIOS2_IMM5,
+	 0,
+	 2,
+	 5,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_IMM5",
+	 FALSE,
+	 0x000007c0,
+	 0x000007c0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CACHE_OPX,
+	 0,
+	 2,
+	 5,
+	 FALSE,
+	 22,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_CACHE_OPX",
+	 FALSE,
+	 0x07c00000,
+	 0x07c00000,
+	 FALSE),
+
+  HOWTO (R_NIOS2_IMM6,
+	 0,
+	 2,
+	 6,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_IMM6",
+	 FALSE,
+	 0x00000fc0,
+	 0x00000fc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_IMM8,
+	 0,
+	 2,
+	 8,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_IMM8",
+	 FALSE,
+	 0x00003fc0,
+	 0x00003fc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_HI16,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_hi16_relocate,
+	 "R_NIOS2_HI16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_LO16,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_lo16_relocate,
+	 "R_NIOS2_LO16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_HIADJ16,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_hiadj16_relocate,
+	 "R_NIOS2_HIADJ16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_BFD_RELOC_32,
+	 0,
+	 2,			/* long */
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_BFD_RELOC32",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_BFD_RELOC_16,
+	 0,
+	 1,			/* short */
+	 16,
+	 FALSE,
+	 0,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_BFD_RELOC16",
+	 FALSE,
+	 0x0000ffff,
+	 0x0000ffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_BFD_RELOC_8,
+	 0,
+	 0,			/* byte */
+	 8,
+	 FALSE,
+	 0,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_BFD_RELOC8",
+	 FALSE,
+	 0x000000ff,
+	 0x000000ff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GPREL,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_gprel_relocate,
+	 "R_NIOS2_GPREL",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GNU_VTINHERIT,
+	 0,
+	 2,			/* short */
+	 0,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 NULL,
+	 "R_NIOS2_GNU_VTINHERIT",
+	 FALSE,
+	 0,
+	 0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GNU_VTENTRY,
+	 0,
+	 2,			/* byte */
+	 0,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 _bfd_elf_rel_vtable_reloc_fn,
+	 "R_NIOS2_GNU_VTENTRY",
+	 FALSE,
+	 0,
+	 0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_UJMP,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_ujmp_relocate,
+	 "R_NIOS2_UJMP",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CJMP,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_cjmp_relocate,
+	 "R_NIOS2_CJMP",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CALLR,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_callr_relocate,
+	 "R_NIOS2_CALLR",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_ALIGN,
+	 0,
+	 2,
+	 0,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 nios2_elf32_ignore_reloc,
+	 "R_NIOS2_ALIGN",
+	 FALSE,
+	 0,
+	 0,
+	 TRUE),
+
+
+  HOWTO (R_NIOS2_GOT16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOT16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CALL16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_CALL16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GOTOFF_LO,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOTOFF_LO",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GOTOFF_HA,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOTOFF_HA",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_PCREL_LO,
+	 0,
+	 2,
+	 16,
+	 TRUE,
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_pcrel_lo16_relocate,
+	 "R_NIOS2_PCREL_LO",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 TRUE),
+
+  HOWTO (R_NIOS2_PCREL_HA,
+	 0,
+	 2,
+	 16,
+	 FALSE, /* This is a PC-relative relocation, but we need to subtract
+		   PC ourselves before the HIADJ.  */
+	 6,
+	 complain_overflow_dont,
+	 nios2_elf32_pcrel_hiadj16_relocate,
+	 "R_NIOS2_PCREL_HA",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 TRUE),
+
+  HOWTO (R_NIOS2_TLS_GD16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_GD16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_LDM16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_LDM16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_LDO16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_LDO16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_IE16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_IE16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_LE16,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_bitfield,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_LE16",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_DTPMOD,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_DTPMOD",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_DTPREL,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_DTPREL",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_TLS_TPREL,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_TLS_TPREL",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_COPY,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_COPY",
+	 FALSE,
+	 0,
+	 0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GLOB_DAT,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GLOB_DAT",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_JUMP_SLOT,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_JUMP_SLOT",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_RELATIVE,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_RELATIVE",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GOTOFF,
+	 0,
+	 2,
+	 32,
+	 FALSE,
+	 0,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOTOFF",
+	 FALSE,
+	 0xffffffff,
+	 0xffffffff,
+	 FALSE),
+
+/* Add other relocations here.  */
+};
+
+static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1];
+
+/* Return the howto for relocation RTYPE.  */
+static reloc_howto_type *
+lookup_howto (unsigned int rtype)
+{
+  static int initialized = 0;
+  int i;
+  int howto_tbl_size = (int) (sizeof (elf_nios2_howto_table_rel)
+			      / sizeof (elf_nios2_howto_table_rel[0]));
+
+  if (!initialized)
+    {
+      initialized = 1;
+      memset (elf_code_to_howto_index, 0xff,
+	      sizeof (elf_code_to_howto_index));
+      for (i = 0; i < howto_tbl_size; i++)
+	elf_code_to_howto_index[elf_nios2_howto_table_rel[i].type] = i;
+    }
+
+  BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL);
+  i = elf_code_to_howto_index[rtype];
+  if (i >= howto_tbl_size)
+    return 0;
+  return elf_nios2_howto_table_rel + i;
+}
+
+/* Map for converting BFD reloc types to Nios II reloc types.  */
+struct elf_reloc_map
+{
+  bfd_reloc_code_real_type bfd_val;
+  enum elf_nios2_reloc_type elf_val;
+};
+
+static const struct elf_reloc_map nios2_reloc_map[] = {
+  {BFD_RELOC_NIOS2_S16, R_NIOS2_S16},
+  {BFD_RELOC_NIOS2_U16, R_NIOS2_U16},
+  {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16},
+  {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26},
+  {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5},
+  {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX},
+  {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6},
+  {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8},
+  {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16},
+  {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16},
+  {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16},
+  {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32},
+  {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16},
+  {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8},
+  {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL},
+  {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT},
+  {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY},
+  {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP},
+  {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP},
+  {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR},
+  {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN},
+  {BFD_RELOC_NIOS2_GOT16, R_NIOS2_GOT16},
+  {BFD_RELOC_NIOS2_CALL16, R_NIOS2_CALL16},
+  {BFD_RELOC_NIOS2_GOTOFF_LO, R_NIOS2_GOTOFF_LO},
+  {BFD_RELOC_NIOS2_GOTOFF_HA, R_NIOS2_GOTOFF_HA},
+  {BFD_RELOC_NIOS2_PCREL_LO, R_NIOS2_PCREL_LO},
+  {BFD_RELOC_NIOS2_PCREL_HA, R_NIOS2_PCREL_HA},
+  {BFD_RELOC_NIOS2_TLS_GD16, R_NIOS2_TLS_GD16},
+  {BFD_RELOC_NIOS2_TLS_LDM16, R_NIOS2_TLS_LDM16},
+  {BFD_RELOC_NIOS2_TLS_LDO16, R_NIOS2_TLS_LDO16},
+  {BFD_RELOC_NIOS2_TLS_IE16, R_NIOS2_TLS_IE16},
+  {BFD_RELOC_NIOS2_TLS_LE16, R_NIOS2_TLS_LE16},
+  {BFD_RELOC_NIOS2_TLS_DTPMOD, R_NIOS2_TLS_DTPMOD},
+  {BFD_RELOC_NIOS2_TLS_DTPREL, R_NIOS2_TLS_DTPREL},
+  {BFD_RELOC_NIOS2_TLS_TPREL, R_NIOS2_TLS_TPREL},
+  {BFD_RELOC_NIOS2_COPY, R_NIOS2_COPY},
+  {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT},
+  {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT},
+  {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE},
+  {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF}
+};
+
+/* The Nios II linker needs to keep track of the number of relocs that it
+   decides to copy as dynamic relocs in check_relocs for each symbol.
+   This is so that it can later discard them if they are found to be
+   unnecessary.  We store the information in a field extending the
+   regular ELF linker hash table.  */
+
+struct elf32_nios2_dyn_relocs
+{
+  struct elf32_nios2_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  bfd_size_type count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  bfd_size_type pc_count;
+};
+
+/* Nios II ELF linker hash entry.  */
+
+struct elf32_nios2_link_hash_entry
+{
+  struct elf_link_hash_entry root;
+
+  /* Track dynamic relocs copied for this symbol.  */
+  struct elf32_nios2_dyn_relocs *dyn_relocs;
+
+#define GOT_UNKNOWN     0
+#define GOT_NORMAL      1
+#define GOT_TLS_GD      2
+#define GOT_TLS_IE      4
+  unsigned char tls_type;
+
+  /* We need to detect and take special action for symbols which are only
+     referenced with %call() and not with %got().  Such symbols do not need
+     a dynamic GOT reloc in shared objects, only a dynamic PLT reloc.  Lazy
+     linking will not work if the dynamic GOT reloc exists.
+     To check for this condition efficiently, we compare got_types_used against
+     CALL16_USED, meaning
+     (got_types_used & (GOT16_USED | CALL16_USED)) == CALL16_USED.  */
+#define GOT16_USED      1
+#define CALL16_USED     2
+  unsigned char got_types_used;
+};
+
+#define elf32_nios2_hash_entry(ent) \
+  ((struct elf32_nios2_link_hash_entry *) (ent))
+
+/* Get the Nios II elf linker hash table from a link_info structure.  */
+#define elf32_nios2_hash_table(info) \
+  ((struct elf32_nios2_link_hash_table *) ((info)->hash))
+
+/* Nios II ELF linker hash table.  */
+struct elf32_nios2_link_hash_table
+  {
+    /* The main hash table.  */
+    struct elf_link_hash_table root;
+
+    /* Short-cuts to get to dynamic linker sections.  */
+    asection *sdynbss;
+    asection *srelbss;
+    asection *sbss;
+
+    union {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } tls_ldm_got;
+
+    /* Small local sym cache.  */
+    struct sym_cache sym_cache;
+
+    bfd_vma res_n_size;
+  };
+
+struct nios2_elf32_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+
+  /* TRUE if TLS GD relocs have been seen for this object.  */
+  bfd_boolean has_tlsgd;
+};
+
+#define elf32_nios2_tdata(abfd) \
+  ((struct nios2_elf32_obj_tdata *) (abfd)->tdata.any)
+
+#define elf32_nios2_local_got_tls_type(abfd) \
+  (elf32_nios2_tdata (abfd)->local_got_tls_type)
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
+
+/* PLT implementation for position-dependent code.  */
+static const bfd_vma nios2_plt_entry[] = { /* .PLTn: */
+  0x03c00034,   /* movhi r15, %hiadj(plt_got_slot_address) */
+  0x7bc00017,   /* ldw r15, %lo(plt_got_slot_address)(r15) */
+  0x7800683a    /* jmp r15 */
+};
+
+static const bfd_vma nios2_plt0_entry[] = { /* .PLTresolve */
+  0x03800034,   /* movhi r14, %hiadj(res_0) */
+  0x73800004,   /* addi r14, r14, %lo(res_0) */
+  0x7b9fc83a,   /* sub r15, r15, r14 */
+  0x03400034,   /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */
+  0x6b800017,   /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */
+  0x6b400017,   /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */
+  0x6800683a    /* jmp r13 */
+};
+
+/* PLT implementation for position-independent code.  */
+static const bfd_vma nios2_so_plt_entry[] = { /* .PLTn */
+  0x03c00034,   /* movhi r15, %hiadj(index * 4) */
+  0x7bc00004,   /* addi r15, r15, %lo(index * 4) */
+  0x00000006    /* br .PLTresolve */
+};
+
+static const bfd_vma nios2_so_plt0_entry[] = { /* .PLTresolve */
+  0x001ce03a,   /* nextpc r14 */
+  0x03400034,   /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */
+  0x6b9b883a,   /* add r13, r13, r14 */
+  0x6b800017,   /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */
+  0x6b400017,   /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */
+  0x6800683a    /* jmp r13 */
+};
+
+/* Implement elf_backend_grok_prstatus:
+   Support for core dump NOTE sections.  */
+static bfd_boolean
+nios2_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+  int offset;
+  size_t size;
+
+  switch (note->descsz)
+    {
+    default:
+      return FALSE;
+
+    case 212:         /* Linux/Nios II */
+      /* pr_cursig */
+      elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+      /* pr_pid */
+      elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+      /* pr_reg */
+      offset = 72;
+      size = 136;
+
+      break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+                                          size, note->descpos + offset);
+}
+
+/* Implement elf_backend_grok_psinfo.  */
+static bfd_boolean
+nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->descsz)
+    {
+    default:
+      return FALSE;
+
+    case 124:         /* Linux/Nios II elf_prpsinfo */
+      elf_tdata (abfd)->core_program
+	= _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+      elf_tdata (abfd)->core_command
+	= _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+    }
+
+  /* Note that for some reason, a spurious space is tacked
+     onto the end of the args in some (at least one anyway)
+     implementations, so strip it off if it exists.  */
+
+  {
+    char *command = elf_tdata (abfd)->core_command;
+    int n = strlen (command);
+
+    if (0 < n && command[n - 1] == ' ')
+      command[n - 1] = '\0';
+  }
+
+  return TRUE;
+}
+
+/* Create an entry in a Nios II ELF linker hash table.  */
+static struct bfd_hash_entry *
+link_hash_newfunc (struct bfd_hash_entry *entry,
+                   struct bfd_hash_table *table, const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                 sizeof (struct elf32_nios2_link_hash_entry));
+      if (entry == NULL)
+        return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = _bfd_elf_link_hash_newfunc (entry, table, string);
+  if (entry)
+    {
+      struct elf32_nios2_link_hash_entry *eh;
+
+      eh = (struct elf32_nios2_link_hash_entry *) entry;
+      eh->dyn_relocs = NULL;
+      eh->tls_type = GOT_UNKNOWN;
+      eh->got_types_used = 0;
+    }
+
+  return entry;
+}
+
+/* Implement bfd_elf32_bfd_reloc_type_lookup:
+   Given a BFD reloc type, return a howto structure.  */
+static reloc_howto_type *
+nios2_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				   bfd_reloc_code_real_type code)
+{
+  int i;
+  for (i = 0;
+       i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map));
+       ++i)
+    if (nios2_reloc_map[i].bfd_val == code)
+      return &elf_nios2_howto_table_rel[(int) nios2_reloc_map[i].elf_val];
+  return NULL;
+}
+
+/* Implement bfd_elf32_bfd_reloc_name_lookup:
+   Given a reloc name, return a howto structure.  */
+static reloc_howto_type *
+nios2_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				   const char *r_name)
+{
+  unsigned int i;
+  for (i = 0;
+       i < (sizeof (elf_nios2_howto_table_rel)
+	    / sizeof (elf_nios2_howto_table_rel[0]));
+       i++)
+    if (elf_nios2_howto_table_rel[i].name
+	&& strcasecmp (elf_nios2_howto_table_rel[i].name, r_name) == 0)
+      return &elf_nios2_howto_table_rel[i];
+
+  return NULL;  
+}
+
+/* Implement elf_info_to_howto:
+   Given a ELF32 relocation, fill in a arelent structure.  */
+static void
+nios2_elf32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+			   Elf_Internal_Rela *dst)
+{
+  unsigned int r_type;
+
+  r_type = ELF32_R_TYPE (dst->r_info);
+  BFD_ASSERT (r_type < R_NIOS2_ILLEGAL);
+  cache_ptr->howto = &elf_nios2_howto_table_rel[r_type];
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtpoff relocation.
+   This is PT_TLS segment p_vaddr.  */
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+static bfd_vma
+tpoff (struct bfd_link_info *info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
+  return address - htab->tls_sec->vma;
+}
+
+/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
+   dangerous relocation.  */
+static bfd_boolean
+nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info)
+{
+
+  bfd_boolean gp_found;
+  struct bfd_hash_entry *h;
+  struct bfd_link_hash_entry *lh;
+
+  /* If we've already figured out what GP will be, just return it. */
+  *pgp = _bfd_get_gp_value (output_bfd);
+  if (*pgp)
+    return TRUE;
+
+  h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE);
+  lh = (struct bfd_link_hash_entry *) h;
+lookup:
+  if (lh)
+    {
+      switch (lh->type)
+	{
+	case bfd_link_hash_undefined:
+	case bfd_link_hash_undefweak:
+	case bfd_link_hash_common:
+	  gp_found = FALSE;
+	  break;
+	case bfd_link_hash_defined:
+	case bfd_link_hash_defweak:
+	  gp_found = TRUE;
+	  *pgp = lh->u.def.value;
+	  break;
+	case bfd_link_hash_indirect:
+	case bfd_link_hash_warning:
+	  lh = lh->u.i.link;
+	  /* @@FIXME  ignoring warning for now */
+	  goto lookup;
+	case bfd_link_hash_new:
+	default:
+	  abort ();
+	}
+    }
+  else
+    gp_found = FALSE;
+
+  if (!gp_found)
+    {
+      /* Only get the error once. */
+      *pgp = 4;
+      _bfd_set_gp_value (output_bfd, *pgp);
+      return FALSE;
+    }
+
+  _bfd_set_gp_value (output_bfd, *pgp);
+
+  return TRUE;
+}
+
+/* Retrieve the previously cached _gp pointer, returning bfd_reloc_dangerous
+   if it's not available as we don't have a link_info pointer available here
+   to look it up in the output symbol table.  We don't need to adjust the
+   symbol value for an external symbol if we are producing relocatable
+   output.  */
+static bfd_reloc_status_type
+nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, 
+                    char **error_message, bfd_vma *pgp)
+{
+  if (bfd_is_und_section (symbol->section) && !relocatable)
+    {
+      *pgp = 0;
+      return bfd_reloc_undefined;
+    }
+
+  *pgp = _bfd_get_gp_value (output_bfd);
+  if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0))
+    {
+      if (relocatable)
+	{
+	  /* Make up a value.  */
+	  *pgp = symbol->section->output_section->vma + 0x4000;
+	  _bfd_set_gp_value (output_bfd, *pgp);
+	}
+      else
+	{
+	  *error_message
+	    = (char *) _("global pointer relative relocation when _gp not defined");
+	  return bfd_reloc_dangerous;
+	}
+    }
+
+  return bfd_reloc_ok;
+}
+
+/* The usual way of loading a 32-bit constant into a Nios II register is to
+   load the high 16 bits in one instruction and then add the low 16 bits with
+   a signed add. This means that the high halfword needs to be adjusted to
+   compensate for the sign bit of the low halfword. This function returns the
+   adjusted high halfword for a given 32-bit constant.  */
+static bfd_vma hiadj(bfd_vma symbol_value)
+{
+  return ((((symbol_value >> 16) & 0xffff)
+	  + ((symbol_value >> 15) & 0x01))
+	  & 0xffff);
+}
+
+/* Do the relocations that require special handling.  */
+static bfd_reloc_status_type
+nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, 
+                              asection *input_section ATTRIBUTE_UNUSED, 
+			      bfd_byte *data, bfd_vma offset, 
+			      bfd_vma symbol_value, bfd_vma addend)
+{
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_value = (symbol_value >> 16) & 0xffff;
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+				   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_lo16_relocate (bfd *abfd, reloc_howto_type *howto,
+			      asection *input_section ATTRIBUTE_UNUSED, 
+			      bfd_byte *data, bfd_vma offset, 
+			      bfd_vma symbol_value, bfd_vma addend)
+{
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_value = symbol_value & 0xffff;
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+				   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto,
+			         asection *input_section ATTRIBUTE_UNUSED, 
+				 bfd_byte *data, bfd_vma offset,
+				 bfd_vma symbol_value, bfd_vma addend)
+{
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_value = hiadj(symbol_value);
+  return _bfd_final_link_relocate (howto, abfd, input_section, data, offset,
+				   symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_pcrel_lo16_relocate (bfd *abfd, reloc_howto_type *howto,
+				    asection *input_section ATTRIBUTE_UNUSED,
+				    bfd_byte *data, bfd_vma offset,
+				    bfd_vma symbol_value, bfd_vma addend)
+{
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_value = symbol_value & 0xffff;
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+                                   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_pcrel_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto,
+				       asection *input_section
+				       ATTRIBUTE_UNUSED,
+				       bfd_byte *data, bfd_vma offset,
+				       bfd_vma symbol_value, bfd_vma addend)
+{
+  symbol_value = symbol_value + addend;
+  symbol_value -= (input_section->output_section->vma
+		   + input_section->output_offset);
+  symbol_value -= offset;
+  addend = 0;
+  symbol_value = hiadj(symbol_value);
+  return _bfd_final_link_relocate (howto, abfd, input_section, data, offset,
+                                   symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_pcrel16_relocate (bfd *abfd, reloc_howto_type *howto,
+                                 asection *input_section ATTRIBUTE_UNUSED, 
+				 bfd_byte *data, bfd_vma offset, 
+				 bfd_vma symbol_value, bfd_vma addend)
+{
+  /* NIOS2 pc relative relocations are relative to the next 32-bit instruction 
+     so we need to subtract 4 before doing a final_link_relocate. */
+  symbol_value = symbol_value + addend - 4;
+  addend = 0;
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+				   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto,
+                                asection *input_section ATTRIBUTE_UNUSED, 
+				bfd_byte *data, bfd_vma offset, 
+				bfd_vma symbol_value, bfd_vma addend)
+{
+  /* Check that the relocation is in the same page as the current address.  */
+  if (((symbol_value + addend) & 0xf0000000)
+      != ((input_section->output_section->vma + offset) & 0xf0000000))
+    return bfd_reloc_overflow;
+
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+				   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_gprel_relocate (bfd *abfd, reloc_howto_type *howto,
+			       asection *input_section ATTRIBUTE_UNUSED, 
+			       bfd_byte *data, bfd_vma offset, 
+			       bfd_vma symbol_value, bfd_vma addend)
+{
+  /* Because we need the output_bfd, the special handling is done
+     in nios2_elf32_relocate_section or in nios2_elf32_gprel_relocate.  */
+  return _bfd_final_link_relocate (howto, abfd, input_section,
+				   data, offset, symbol_value, addend);
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_ujmp_relocate (bfd *abfd, reloc_howto_type *howto,
+                              asection *input_section ATTRIBUTE_UNUSED, 
+			      bfd_byte *data, bfd_vma offset, 
+			      bfd_vma symbol_value, bfd_vma addend)
+{
+  bfd_vma symbol_lo16, symbol_hi16;
+  bfd_reloc_status_type r;
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_hi16 = (symbol_value >> 16) & 0xffff;
+  symbol_lo16 = symbol_value & 0xffff;
+
+  r = _bfd_final_link_relocate (howto, abfd, input_section,
+				data, offset, symbol_hi16, addend);
+
+  if (r == bfd_reloc_ok)
+    return _bfd_final_link_relocate (howto, abfd, input_section,
+				     data, offset + 4, symbol_lo16, addend);
+
+  return r;
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_cjmp_relocate (bfd *abfd, reloc_howto_type *howto,
+			      asection *input_section ATTRIBUTE_UNUSED, 
+			      bfd_byte *data, bfd_vma offset, 
+			      bfd_vma symbol_value, bfd_vma addend)
+{
+  bfd_vma symbol_lo16, symbol_hi16;
+  bfd_reloc_status_type r;
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_hi16 = (symbol_value >> 16) & 0xffff;
+  symbol_lo16 = symbol_value & 0xffff;
+
+  r = _bfd_final_link_relocate (howto, abfd, input_section,
+				data, offset, symbol_hi16, addend);
+
+  if (r == bfd_reloc_ok)
+    return _bfd_final_link_relocate (howto, abfd, input_section,
+				     data, offset + 4, symbol_lo16, addend);
+
+  return r;
+}
+
+static bfd_reloc_status_type
+nios2_elf32_do_callr_relocate (bfd *abfd, reloc_howto_type *howto,
+			       asection *input_section ATTRIBUTE_UNUSED, 
+			       bfd_byte *data, bfd_vma offset, 
+			       bfd_vma symbol_value, bfd_vma addend)
+{
+  bfd_vma symbol_lo16, symbol_hi16;
+  bfd_reloc_status_type r;
+  symbol_value = symbol_value + addend;
+  addend = 0;
+  symbol_hi16 = (symbol_value >> 16) & 0xffff;
+  symbol_lo16 = symbol_value & 0xffff;
+
+  r = _bfd_final_link_relocate (howto, abfd, input_section,
+				data, offset, symbol_hi16, addend);
+
+  if (r == bfd_reloc_ok)
+    return _bfd_final_link_relocate (howto, abfd, input_section,
+				     data, offset + 4, symbol_lo16, addend);
+
+  return r;
+}
+
+/* HOWTO handlers for relocations that require special handling.  */
+
+/* This is for relocations used only when relaxing to ensure
+   changes in size of section don't screw up .align.  */
+static bfd_reloc_status_type
+nios2_elf32_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+                          asymbol *symbol ATTRIBUTE_UNUSED, 
+                          void *data ATTRIBUTE_UNUSED, asection *input_section, 
+			  bfd *output_bfd, 
+			  char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+nios2_elf32_hi16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 
+			   void *data, asection *input_section, 
+			   bfd *output_bfd, 
+			   char **error_message ATTRIBUTE_UNUSED)
+{
+  /* This part is from bfd_elf_generic_reloc.  */
+  if (output_bfd != NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0
+      && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
+  if (output_bfd != NULL)
+    /* FIXME: See bfd_perform_relocation.  Is this right?  */
+    return bfd_reloc_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 != 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 != 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 != 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 != 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 != 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 != 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 != 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);
+
+  /* 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_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 != 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 != 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);
+}
+
+ 
+/* Implement elf_backend_relocate_section.  */
+static bfd_boolean
+nios2_elf32_relocate_section (bfd *output_bfd,
+			      struct bfd_link_info *info,
+			      bfd *input_bfd,
+			      asection *input_section,
+			      bfd_byte *contents,
+			      Elf_Internal_Rela *relocs,
+			      Elf_Internal_Sym *local_syms,
+			      asection **local_sections)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  struct elf32_nios2_link_hash_table *htab;
+  asection *sgot;
+  asection *splt;
+  asection *sreloc = NULL;
+  bfd_vma *local_got_offsets;
+  bfd *dynobj = NULL;
+
+  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);
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  for (rel = relocs; rel < relend; rel++)
+    {
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      struct elf_link_hash_entry *h;
+      struct elf32_nios2_link_hash_entry *eh;
+      bfd_vma relocation;
+      bfd_vma gp;
+      bfd_vma reloc_address;
+      bfd_reloc_status_type r = bfd_reloc_ok;
+      const char *name = NULL;
+      int r_type;
+      const char *format;
+      char msgbuf[256];
+      const char* msg = (const char*) NULL;
+      bfd_boolean unresolved_reloc;
+      bfd_vma off;
+      int use_plt;
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
+      h = NULL;
+      sym = NULL;
+      sec = NULL;
+
+      if (r_symndx < symtab_hdr->sh_info)
+	{
+	  sym = local_syms + r_symndx;
+	  sec = local_sections[r_symndx];
+	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+	}
+      else
+	{
+          bfd_boolean warned;
+
+          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+				   r_symndx, symtab_hdr, sym_hashes,
+				   h, sec, relocation,
+				   unresolved_reloc, warned);
+	}
+
+      if (sec && discarded_section (sec))
+	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+					 rel, 1, relend, howto, 0, contents);
+
+      /* Nothing more to do unless this is a final link.  */
+      if (info->relocatable)
+	continue;
+
+      if (sec && sec->output_section)
+	reloc_address = (sec->output_section->vma + sec->output_offset
+			 + rel->r_offset);
+      else
+	reloc_address = 0;
+		
+      if (howto)
+	{
+	  switch (howto->type)
+	    {
+	    case R_NIOS2_HI16:
+	      r = nios2_elf32_do_hi16_relocate (input_bfd, howto,
+						input_section,
+						contents, rel->r_offset,
+						relocation, rel->r_addend);
+	      break;
+	    case R_NIOS2_LO16:
+              r = nios2_elf32_do_lo16_relocate (input_bfd, howto,
+						input_section,
+						contents, rel->r_offset,
+						relocation, rel->r_addend);
+	      break;
+	    case R_NIOS2_PCREL_LO:
+	      r = nios2_elf32_do_pcrel_lo16_relocate (input_bfd, howto,
+						      input_section,
+						      contents,
+						      rel->r_offset,
+						      relocation,
+						      rel->r_addend);
+	      break;
+	    case R_NIOS2_HIADJ16:
+              r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto,
+						   input_section, contents,
+						   rel->r_offset, relocation,
+						   rel->r_addend);
+	      break;
+	    case R_NIOS2_PCREL_HA:
+	      r = nios2_elf32_do_pcrel_hiadj16_relocate (input_bfd, howto,
+							 input_section,
+							 contents,
+							 rel->r_offset,
+							 relocation,
+							 rel->r_addend);
+	      break;
+	    case R_NIOS2_PCREL16:
+	      r = nios2_elf32_do_pcrel16_relocate (input_bfd, howto,
+						   input_section, contents,
+						   rel->r_offset, relocation,
+						   rel->r_addend);
+	      break;
+	    case R_NIOS2_GPREL:
+	      /* Turns an absolute address into a gp-relative address.  */
+	      if (!nios2_elf_assign_gp (output_bfd, &gp, info))
+		{
+		  format = _("global pointer relative relocation at address "
+			     "0x%08x when _gp not defined\n");
+		  sprintf (msgbuf, format, reloc_address);
+		  msg = msgbuf;
+		  r = bfd_reloc_dangerous;
+		}
+	      else
+		{
+		  bfd_vma symbol_address = rel->r_addend + relocation;
+		  relocation = relocation + rel->r_addend - gp;
+		  rel->r_addend = 0;
+		  if (((signed) relocation < -32768
+		       || (signed) relocation > 32767)
+		      && (!h
+			  || h->root.type == bfd_link_hash_defined
+			  || h->root.type == bfd_link_hash_defweak))
+		    {
+		      format = _("Unable to reach %s (at 0x%08x) from the "
+				 "global pointer (at 0x%08x) because the "
+				 "offset (%d) is out of the allowed range, "
+				 "-32678 to 32767.\n" );
+		      sprintf (msgbuf, format, name, symbol_address, gp, 
+			       (signed)relocation);
+		      msg = msgbuf;
+		      r = bfd_reloc_outofrange;
+		    }
+		  else
+		    r =	_bfd_final_link_relocate (howto, input_bfd,
+						  input_section, contents,
+						  rel->r_offset, relocation,
+						  rel->r_addend);
+		}
+
+	      break;
+	    case R_NIOS2_UJMP:
+	      r = nios2_elf32_do_ujmp_relocate (input_bfd, howto,
+						input_section,
+						contents, rel->r_offset,
+						relocation, rel->r_addend);
+	      break;
+	    case R_NIOS2_CJMP:
+	      r = nios2_elf32_do_cjmp_relocate (input_bfd, howto,
+						input_section,
+						contents, rel->r_offset,
+						relocation, rel->r_addend);
+	      break;
+	    case R_NIOS2_CALLR:
+	      r = nios2_elf32_do_callr_relocate (input_bfd, howto,
+						 input_section, contents,
+						 rel->r_offset, relocation,
+						 rel->r_addend);
+	      break;
+	    case R_NIOS2_CALL26:
+	      /* If we have a call to an undefined weak symbol, we just want
+		 to stuff a zero in the bits of the call instruction and
+		 bypass the normal call26 relocation handling, because it'll
+		 diagnose an overflow error if address 0 isn't in the same
+		 256MB segment as the call site.  Presumably the call
+		 should be guarded by a null check anyway.  */
+	      if (h != NULL && h->root.type == bfd_link_hash_undefweak)
+		{
+		  BFD_ASSERT (relocation == 0 && rel->r_addend == 0);
+		  r = _bfd_final_link_relocate (howto, input_bfd,
+						input_section, contents,
+						rel->r_offset, relocation,
+						rel->r_addend);
+		  break;
+		}
+              /* Handle relocations which should use the PLT entry.
+                 NIOS2_BFD_RELOC_32 relocations will use the symbol's value,
+                 which may point to a PLT entry, but we don't need to handle
+                 that here.  If we created a PLT entry, all branches in this
+                 object should go to it.  */
+              if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
+                {
+                  /* If we've created a .plt section, and assigned a PLT entry
+                     to this function, it should not be known to bind locally.
+                     If it were, we would have cleared the PLT entry.  */
+                  BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h));
+
+                  relocation = (splt->output_section->vma
+                                + splt->output_offset
+                                + h->plt.offset);
+
+                  unresolved_reloc = FALSE;
+		}
+	      r = nios2_elf32_do_call26_relocate (input_bfd, howto,
+						  input_section, contents,
+						  rel->r_offset, relocation,
+						  rel->r_addend);
+	      break;
+	    case R_NIOS2_ALIGN:
+	      r = bfd_reloc_ok;
+	      /* For symmetry this would be
+		 r = nios2_elf32_do_ignore_reloc (input_bfd, howto,
+		                                  input_section, contents,
+						  rel->r_offset, relocation,
+						  rel->r_addend);
+                but do_ignore_reloc would do no more than return
+		bfd_reloc_ok. */
+	      break;
+
+            case R_NIOS2_GOT16:
+	    case R_NIOS2_CALL16:
+	      /* Relocation is to the entry for this symbol in the
+		 global offset table.  */
+	      if (sgot == NULL)
+		{
+		  r = bfd_reloc_notsupported;
+		  break;
+		}
+
+              use_plt = 0;
+
+	      if (h != NULL)
+		{
+		  bfd_boolean dyn;
+
+                  eh = (struct elf32_nios2_link_hash_entry *)h;
+                  use_plt = (eh->got_types_used == CALL16_USED
+                             && h->plt.offset != (bfd_vma) -1);
+
+		  off = h->got.offset;
+		  BFD_ASSERT (off != (bfd_vma) -1);
+		  dyn = elf_hash_table (info)->dynamic_sections_created;
+		  if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+		      || (info->shared
+			  && SYMBOL_REFERENCES_LOCAL (info, h))
+		      || (ELF_ST_VISIBILITY (h->other)
+			  && h->root.type == bfd_link_hash_undefweak))
+		    {
+        	      /* This is actually a static link, or it is a -Bsymbolic
+			 link and the symbol is defined locally.  We must
+			 initialize this entry in the global offset table.
+			 Since the offset must always be a multiple of 4, we
+			 use the least significant bit to record whether we
+			 have initialized it already.
+
+        		 When doing a dynamic link, we create a .rela.got
+			 relocation entry to initialize the value.  This is
+			 done in the finish_dynamic_symbol routine.  */
+        	      if ((off & 1) != 0)
+        		off &= ~1;
+        	      else
+        		{
+        		  bfd_put_32 (output_bfd, relocation,
+				      sgot->contents + off);
+        		  h->got.offset |= 1;
+        		}
+        	    }
+        	  else
+        	    unresolved_reloc = FALSE;
+        	}
+              else
+        	{
+        	  BFD_ASSERT (local_got_offsets != NULL
+			      && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+        	  off = local_got_offsets[r_symndx];
+
+        	  /* The offset must always be a multiple of 4.  We use the
+        	     least significant bit to record whether we have already
+        	     generated the necessary reloc.  */
+        	  if ((off & 1) != 0)
+        	    off &= ~1;
+        	  else
+        	    {
+              	      bfd_put_32 (output_bfd, relocation,
+				  sgot->contents + off);
+
+               	      if (info->shared)
+        		{
+        		  asection *srelgot;
+        		  Elf_Internal_Rela outrel;
+        		  bfd_byte *loc;
+
+        		  srelgot = htab->root.srelgot;
+        		  BFD_ASSERT (srelgot != NULL);
+
+        		  outrel.r_addend = relocation;
+        		  outrel.r_offset = (sgot->output_section->vma
+        				     + sgot->output_offset
+        				     + off);
+        		  outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE);
+        		  loc = srelgot->contents;
+        		  loc += (srelgot->reloc_count++ *
+				  sizeof (Elf32_External_Rela));
+        		  bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+        		}
+
+        	      local_got_offsets[r_symndx] |= 1;
+        	    }
+        	}
+
+              if (use_plt && info->shared)
+                {
+		  off = ((h->plt.offset - 24) / 12 + 3) * 4;
+		  relocation = htab->root.sgotplt->output_offset + off;
+                }
+	      else
+		relocation = sgot->output_offset + off;
+
+	      /* This relocation does not use the addend.  */
+	      rel->r_addend = 0;
+
+              r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+					    contents, rel->r_offset,
+					    relocation, rel->r_addend);
+	      break;
+
+	    case R_NIOS2_GOTOFF_LO:
+	    case R_NIOS2_GOTOFF_HA:
+	    case R_NIOS2_GOTOFF:
+	      /* Relocation is relative to the start of the
+		 global offset table.  */
+
+	      BFD_ASSERT (sgot != NULL);
+	      if (sgot == NULL)
+		{
+		  r = bfd_reloc_notsupported;
+		  break;
+		}
+
+	      /* Note that sgot->output_offset is not involved in this
+		 calculation.  We always want the start of .got.  If we
+		 define _GLOBAL_OFFSET_TABLE in a different way, as is
+		 permitted by the ABI, we might have to change this
+		 calculation.  */
+	      relocation -= sgot->output_section->vma;
+	      switch (howto->type)
+		{
+		case R_NIOS2_GOTOFF_LO:
+		  r = nios2_elf32_do_lo16_relocate (input_bfd, howto,
+						    input_section, contents,
+						    rel->r_offset, relocation,
+						    rel->r_addend);
+		  break;
+		case R_NIOS2_GOTOFF_HA:
+		  r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto,
+						       input_section, contents,
+						       rel->r_offset,
+						       relocation,
+						       rel->r_addend);
+		  break;
+		default:
+		  r = _bfd_final_link_relocate (howto, input_bfd,
+						input_section, contents,
+						rel->r_offset, relocation,
+						rel->r_addend);
+		  break;
+		}
+	      break;
+
+	    case R_NIOS2_TLS_LDO16:
+	      relocation -= dtpoff_base (info) + DTP_OFFSET;
+
+	      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+					    contents, rel->r_offset,
+					    relocation, rel->r_addend);
+	      break;
+	    case R_NIOS2_TLS_LDM16:
+	      if (htab->root.sgot == NULL)
+		abort ();
+
+	      off = htab->tls_ldm_got.offset;
+
+	      if ((off & 1) != 0)
+		off &= ~1;
+	      else
+		{
+		  /* If we don't know the module number, create a relocation
+		     for it.  */
+		  if (info->shared)
+		    {
+		      Elf_Internal_Rela outrel;
+		      bfd_byte *loc;
+
+		      if (htab->root.srelgot == NULL)
+			abort ();
+
+		      outrel.r_addend = 0;
+		      outrel.r_offset = (htab->root.sgot->output_section->vma
+					 + htab->root.sgot->output_offset
+					 + off);
+		      outrel.r_info = ELF32_R_INFO (0, R_NIOS2_TLS_DTPMOD);
+
+		      loc = htab->root.srelgot->contents;
+		      loc += (htab->root.srelgot->reloc_count++
+			      * sizeof (Elf32_External_Rela));
+		      bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+		    }
+		  else
+		    bfd_put_32 (output_bfd, 1,
+				htab->root.sgot->contents + off);
+
+		  htab->tls_ldm_got.offset |= 1;
+		}
+
+	      relocation = (htab->root.sgot->output_offset + off);
+
+	      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+					    contents, rel->r_offset,
+					    relocation, rel->r_addend);
+
+	      break;
+	    case R_NIOS2_TLS_GD16:
+            case R_NIOS2_TLS_IE16:
+	      {
+		int indx;
+		char tls_type;
+
+		if (htab->root.sgot == NULL)
+		  abort ();
+
+		indx = 0;
+		if (h != NULL)
+		  {
+		    bfd_boolean dyn;
+		    dyn = htab->root.dynamic_sections_created;
+		    if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+			&& (!info->shared
+			    || !SYMBOL_REFERENCES_LOCAL (info, h)))
+		      {
+			unresolved_reloc = FALSE;
+			indx = h->dynindx;
+		      }
+		    off = h->got.offset;
+		    tls_type = (((struct elf32_nios2_link_hash_entry *) h)
+				->tls_type);
+		  }
+		else
+		  {
+		    if (local_got_offsets == NULL)
+		      abort ();
+		    off = local_got_offsets[r_symndx];
+		    tls_type = (elf32_nios2_local_got_tls_type (input_bfd)
+				[r_symndx]);
+		  }
+
+		if (tls_type == GOT_UNKNOWN)
+		  abort ();
+
+		if ((off & 1) != 0)
+		  off &= ~1;
+		else
+		  {
+		    bfd_boolean need_relocs = FALSE;
+		    Elf_Internal_Rela outrel;
+		    bfd_byte *loc = NULL;
+		    int cur_off = off;
+
+		    /* The GOT entries have not been initialized yet.  Do it
+		       now, and emit any relocations.  If both an IE GOT and a
+		       GD GOT are necessary, we emit the GD first.  */
+
+		    if ((info->shared || indx != 0)
+			&& (h == NULL
+			    || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+			    || h->root.type != bfd_link_hash_undefweak))
+		      {
+			need_relocs = TRUE;
+			if (htab->root.srelgot == NULL)
+			  abort ();
+			loc = htab->root.srelgot->contents;
+			loc += (htab->root.srelgot->reloc_count *
+				sizeof (Elf32_External_Rela));
+		      }
+
+		    if (tls_type & GOT_TLS_GD)
+		      {
+			if (need_relocs)
+			  {
+			    outrel.r_addend = 0;
+			    outrel.r_offset = (htab->root.sgot->output_section->vma
+					       + htab->root.sgot->output_offset
+					       + cur_off);
+			    outrel.r_info = ELF32_R_INFO (indx,
+							  R_NIOS2_TLS_DTPMOD);
+
+			    bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+						       loc);
+			    htab->root.srelgot->reloc_count++;
+			    loc += sizeof (Elf32_External_Rela);
+
+			    if (indx == 0)
+			      bfd_put_32 (output_bfd,
+					  (relocation - dtpoff_base (info) -
+					   DTP_OFFSET),
+					  htab->root.sgot->contents + cur_off + 4);
+			    else
+			      {
+				outrel.r_addend = 0;
+				outrel.r_info = ELF32_R_INFO (indx,
+				  R_NIOS2_TLS_DTPREL);
+				outrel.r_offset += 4;
+
+				bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+							   loc);
+				htab->root.srelgot->reloc_count++;
+				loc += sizeof (Elf32_External_Rela);
+			      }
+			  }
+			else
+			  {
+			    /* If we are not emitting relocations for a
+			       general dynamic reference, then we must be in a
+			       static link or an executable link with the
+			       symbol binding locally.  Mark it as belonging
+			       to module 1, the executable.  */
+			    bfd_put_32 (output_bfd, 1,
+					htab->root.sgot->contents + cur_off);
+			    bfd_put_32 (output_bfd, (relocation -
+						     dtpoff_base (info) -
+						     DTP_OFFSET),
+					htab->root.sgot->contents + cur_off + 4);
+			  }
+
+			cur_off += 8;
+		      }
+
+		    if (tls_type & GOT_TLS_IE)
+		      {
+			if (need_relocs)
+			  {
+			    if (indx == 0)
+			      outrel.r_addend = (relocation -
+						 dtpoff_base (info));
+			    else
+			      outrel.r_addend = 0;
+			    outrel.r_offset = (htab->root.sgot->output_section->vma
+					       + htab->root.sgot->output_offset
+					       + cur_off);
+			    outrel.r_info = ELF32_R_INFO (indx,
+							  R_NIOS2_TLS_TPREL);
+
+			    bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+						       loc);
+			    htab->root.srelgot->reloc_count++;
+			    loc += sizeof (Elf32_External_Rela);
+			  }
+			else
+			  bfd_put_32 (output_bfd, (tpoff (info, relocation)
+						   - TP_OFFSET),
+				      htab->root.sgot->contents + cur_off);
+			cur_off += 4;
+		      }
+
+		    if (h != NULL)
+		      h->got.offset |= 1;
+		    else
+		      local_got_offsets[r_symndx] |= 1;
+		  }
+
+		if ((tls_type & GOT_TLS_GD) && r_type != R_NIOS2_TLS_GD16)
+		  off += 8;
+		relocation = (htab->root.sgot->output_offset + off);
+
+		r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+					      contents, rel->r_offset,
+					      relocation, rel->r_addend);
+	      }
+
+	      break;
+            case R_NIOS2_TLS_LE16:
+	      if (info->shared && !info->pie)
+		{
+		  (*_bfd_error_handler)
+		    (_("%B(%A+0x%lx): R_NIOS2_TLS_LE16 relocation not "
+		       "permitted in shared object"),
+		     input_bfd, input_section,
+		     (long) rel->r_offset, howto->name);
+		  return FALSE;
+		}
+	      else
+		relocation = tpoff (info, relocation) - TP_OFFSET;
+
+	      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+					    contents, rel->r_offset,
+					    relocation, rel->r_addend);
+	      break;
+
+	    case R_NIOS2_BFD_RELOC_32:
+	      if (info->shared
+		  && (input_section->flags & SEC_ALLOC) != 0
+		  && (h == NULL
+		      || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+		      || h->root.type != bfd_link_hash_undefweak))
+		{
+		  Elf_Internal_Rela outrel;
+		  bfd_byte *loc;
+		  bfd_boolean skip, relocate;
+
+		  /* When generating a shared object, these relocations
+		     are copied into the output file to be resolved at run
+		     time.  */
+
+		  skip = FALSE;
+		  relocate = FALSE;
+
+		  outrel.r_offset
+		    = _bfd_elf_section_offset (output_bfd, info,
+					       input_section, rel->r_offset);
+		  if (outrel.r_offset == (bfd_vma) -1)
+		    skip = TRUE;
+		  else if (outrel.r_offset == (bfd_vma) -2)
+		    skip = TRUE, relocate = TRUE;
+		  outrel.r_offset += (input_section->output_section->vma
+				      + input_section->output_offset);
+
+		  if (skip)
+		    memset (&outrel, 0, sizeof outrel);
+		  else if (h != NULL
+			   && h->dynindx != -1
+			   && (!info->shared
+			       || !info->symbolic
+			       || !h->def_regular))
+		    {
+		      outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		      outrel.r_addend = rel->r_addend;
+		    }
+		  else
+		    {
+		      /* This symbol is local, or marked to become local.  */
+		      outrel.r_addend = relocation + rel->r_addend;
+		      relocate = TRUE;
+		      outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE);
+		    }
+
+		  sreloc = elf_section_data (input_section)->sreloc;
+		  if (sreloc == NULL)
+		    abort ();
+
+		  loc = sreloc->contents;
+		  loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
+		  bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+
+		  /* This reloc will be computed at runtime, so there's no
+		     need to do anything now, except for R_NIOS2_BFD_RELOC_32
+		     relocations that have been turned into
+		     R_NIOS2_RELATIVE.  */
+		  if (!relocate)
+		    break;
+		}
+
+              r = _bfd_final_link_relocate (howto, input_bfd,
+                                            input_section, contents,
+                                            rel->r_offset, relocation,
+                                            rel->r_addend);
+	      break;
+
+	    case R_NIOS2_TLS_DTPREL:
+	      relocation -= dtpoff_base (info);
+	      /* Fall through.  */
+
+	    default:
+	      r = _bfd_final_link_relocate (howto, input_bfd,
+					    input_section, contents,
+					    rel->r_offset, relocation,
+					    rel->r_addend);
+	      break;
+	    }
+	}
+      else
+	r = bfd_reloc_notsupported;
+
+      if (r != bfd_reloc_ok)
+	{
+	  if (h != NULL)
+	    name = h->root.root.string;
+	  else
+	    {
+	      name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      sym->st_name);
+	      if (name == NULL || *name == '\0')
+		name = bfd_section_name (input_bfd, sec);
+	    }
+
+	  switch (r)
+	    {
+	    case bfd_reloc_overflow:
+	      r = info->callbacks->reloc_overflow (info, NULL, name,
+						   howto->name, (bfd_vma) 0,
+						   input_bfd, input_section,
+						   rel->r_offset);
+	      break;
+
+	    case bfd_reloc_undefined:
+	      r = info->callbacks->undefined_symbol (info, name, input_bfd,
+						     input_section,
+						     rel->r_offset, TRUE);
+	      break;
+
+	    case bfd_reloc_outofrange:
+	      if (msg == NULL)
+		msg = _("relocation out of range");
+	      break;
+
+	    case bfd_reloc_notsupported:
+	      if (msg == NULL)
+		msg = _("unsupported relocation");
+	      break;
+
+	    case bfd_reloc_dangerous:
+	      if (msg == NULL)
+		msg = _("dangerous relocation");
+	      break;
+
+	    default:
+	      if (msg == NULL)
+		msg = _("unknown error");
+	      break;
+	    }
+
+	  if (msg)
+	    {
+	      r = info->callbacks->warning
+		(info, msg, name, input_bfd, input_section, rel->r_offset);
+	      return FALSE;
+	    }
+	}
+    }
+  return TRUE;
+}
+
+/* Implement elf-backend_section_flags:
+   Convert NIOS2 specific section flags to bfd internal section flags.  */
+static bfd_boolean
+nios2_elf32_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr)
+{
+  if (hdr->sh_flags & SHF_NIOS2_GPREL)
+    *flags |= SEC_SMALL_DATA;
+
+  return TRUE;
+}
+
+/* Implement elf_backend_fake_sections:
+   Set the correct type for an NIOS2 ELF section.  We do this by the
+   section name, which is a hack, but ought to work.  */
+static bfd_boolean
+nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+			   Elf_Internal_Shdr *hdr, asection *sec)
+{
+  register const char *name = bfd_get_section_name (abfd, sec);
+
+  if ((sec->flags & SEC_SMALL_DATA)
+      || strcmp (name, ".sdata") == 0
+      || strcmp (name, ".sbss") == 0
+      || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0)
+    hdr->sh_flags |= SHF_NIOS2_GPREL;
+
+  return TRUE;
+}
+
+/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
+   shortcuts to them in our hash table.  */
+static bfd_boolean
+create_got_section (bfd *dynobj, struct bfd_link_info *info)
+{
+  struct elf32_nios2_link_hash_table *htab;
+
+  htab = elf32_nios2_hash_table (info);
+
+  if (! _bfd_elf_create_got_section (dynobj, info))
+    return FALSE;
+
+  /* In order for the two loads in .PLTresolve to share the same %hiadj,
+     _GLOBAL_OFFSET_TABLE_ must be aligned to a 16-byte boundary.  */
+  if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt, 4))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Implement elf_backend_create_dynamic_sections:
+   Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
+   .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
+   hash table.  */
+static bfd_boolean
+nios2_elf32_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
+{
+  struct elf32_nios2_link_hash_table *htab;
+
+  htab = elf32_nios2_hash_table (info);
+  if (!htab->root.sgot && !create_got_section (dynobj, info))
+    return FALSE;
+
+  _bfd_elf_create_dynamic_sections (dynobj, info);
+
+  /* In order for the two loads in a shared object .PLTresolve to share the
+     same %hiadj, the start of the PLT (as well as the GOT) must be aligned
+     to a 16-byte boundary.  This is because the addresses for these loads
+     include the -(.plt+4) PIC correction.  */
+  if (!bfd_set_section_alignment (dynobj, htab->root.splt, 4))
+    return FALSE;
+
+  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+  if (!htab->sdynbss)
+    return FALSE;
+  if (!info->shared)
+    {
+      htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+      if (!htab->srelbss)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Implement elf_backend_copy_indirect_symbol:
+   Copy the extra info we tack onto an elf_link_hash_entry.  */
+static void
+nios2_elf32_copy_indirect_symbol (struct bfd_link_info *info,
+                                  struct elf_link_hash_entry *dir,
+                                  struct elf_link_hash_entry *ind)
+{
+  struct elf32_nios2_link_hash_entry *edir, *eind;
+
+  edir = (struct elf32_nios2_link_hash_entry *) dir;
+  eind = (struct elf32_nios2_link_hash_entry *) ind;
+
+  if (eind->dyn_relocs != NULL)
+    {
+      if (edir->dyn_relocs != NULL)
+	{
+          struct elf32_nios2_dyn_relocs **pp;
+          struct elf32_nios2_dyn_relocs *p;
+
+          /* Add reloc counts against the indirect sym to the direct sym
+             list.  Merge any entries against the same section.  */
+          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+            {
+              struct elf32_nios2_dyn_relocs *q;
+
+              for (q = edir->dyn_relocs; q != NULL; q = q->next)
+		if (q->sec == p->sec)
+                  {
+                    q->pc_count += p->pc_count;
+                    q->count += p->count;
+                    *pp = p->next;
+                    break;
+                  }
+              if (q == NULL)
+                pp = &p->next;
+            }
+          *pp = edir->dyn_relocs;
+        }
+
+      edir->dyn_relocs = eind->dyn_relocs;
+      eind->dyn_relocs = NULL;
+    }
+
+  if (ind->root.type == bfd_link_hash_indirect
+      && dir->got.refcount <= 0)
+    {
+      edir->tls_type = eind->tls_type;
+      eind->tls_type = GOT_UNKNOWN;
+    }
+
+  edir->got_types_used |= eind->got_types_used;
+
+  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
+/* Implement elf_backend_check_relocs:
+   Look through the relocs for a section during the first phase.  */
+static bfd_boolean
+nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
+                          asection *sec, const Elf_Internal_Rela *relocs)
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  struct elf32_nios2_link_hash_table *htab;
+  asection *sgot;
+  asection *srelgot;
+  asection *sreloc = NULL;
+  bfd_signed_vma *local_got_refcounts;
+
+  if (info->relocatable)
+    return TRUE;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = (sym_hashes
+		    + symtab_hdr->sh_size / sizeof (Elf32_External_Sym));
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  htab = elf32_nios2_hash_table (info);
+  sgot = htab->root.sgot;
+  srelgot = htab->root.srelgot;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned int r_type;
+      struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+	h = NULL;
+      else
+	{
+	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	  while (h->root.type == bfd_link_hash_indirect
+		 || h->root.type == bfd_link_hash_warning)
+	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+	}
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      switch (r_type)
+	{
+        case R_NIOS2_GOT16:
+	case R_NIOS2_CALL16:
+	case R_NIOS2_TLS_GD16:
+	case R_NIOS2_TLS_IE16:
+	  /* This symbol requires a global offset table entry.  */
+	  {
+	    int tls_type, old_tls_type;
+
+	    switch (r_type)
+	      {
+	      default:
+	      case R_NIOS2_GOT16:
+	      case R_NIOS2_CALL16:
+		tls_type = GOT_NORMAL;
+		break;
+	      case R_NIOS2_TLS_GD16:
+		tls_type = GOT_TLS_GD;
+		break;
+	      case R_NIOS2_TLS_IE16:
+		tls_type = GOT_TLS_IE;
+		break;
+	      }
+
+	    if (dynobj == NULL)
+	      {
+		/* Create the .got section.  */
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+		nios2_elf32_create_dynamic_sections (dynobj, info);
+	      }
+
+	    if (sgot == NULL)
+	      {
+		sgot = htab->root.sgot;
+		BFD_ASSERT (sgot != NULL);
+	      }
+
+	    if (srelgot == NULL
+		&& (h != NULL || info->shared))
+	      {
+		srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+		BFD_ASSERT (srelgot != NULL);
+	      }
+
+	    if (h != NULL)
+	      {
+		struct elf32_nios2_link_hash_entry *eh
+		  = (struct elf32_nios2_link_hash_entry *)h;
+		h->got.refcount++;
+		old_tls_type = elf32_nios2_hash_entry(h)->tls_type;
+		if (r_type == R_NIOS2_CALL16)
+		  {
+		    /* Make sure a plt entry is created for this symbol if
+		       it turns out to be a function defined by a dynamic
+		       object.  */
+		    h->plt.refcount++;
+		    h->needs_plt = 1;
+		    h->type = STT_FUNC;
+		    eh->got_types_used |= CALL16_USED;
+		  }
+		else
+		  eh->got_types_used |= GOT16_USED;
+	      }
+	    else
+	      {
+		/* This is a global offset table entry for a local symbol.  */
+		if (local_got_refcounts == NULL)
+		  {
+		    bfd_size_type size;
+
+		    size = symtab_hdr->sh_info;
+		    size *= (sizeof (bfd_signed_vma) + sizeof (char));
+		    local_got_refcounts
+		      = ((bfd_signed_vma *) bfd_zalloc (abfd, size));
+		    if (local_got_refcounts == NULL)
+		      return FALSE;
+		    elf_local_got_refcounts (abfd) = local_got_refcounts;
+		    elf32_nios2_local_got_tls_type (abfd)
+		      = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+		  }
+		local_got_refcounts[r_symndx]++;
+		old_tls_type = elf32_nios2_local_got_tls_type (abfd) [r_symndx];
+	      }
+
+	    /* We will already have issued an error message if there is a
+               TLS / non-TLS mismatch, based on the symbol type.  We don't
+               support any linker relaxations.  So just combine any TLS
+               types needed.  */
+	    if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
+		&& tls_type != GOT_NORMAL)
+	      tls_type |= old_tls_type;
+
+            if (old_tls_type != tls_type)
+              {
+                if (h != NULL)
+                  elf32_nios2_hash_entry (h)->tls_type = tls_type;
+                else
+                  elf32_nios2_local_got_tls_type (abfd) [r_symndx] = tls_type;
+	      }
+	  }
+	  /* Fall through */
+	case R_NIOS2_TLS_LDM16:
+	  if (r_type == R_NIOS2_TLS_LDM16)
+	    htab->tls_ldm_got.refcount++;
+
+          if (htab->root.sgot == NULL)
+            {
+              if (htab->root.dynobj == NULL)
+                htab->root.dynobj = abfd;
+              if (!create_got_section (htab->root.dynobj, info))
+                return FALSE;
+            }
+	  break;
+
+          /* This relocation describes the C++ object vtable hierarchy.
+             Reconstruct it for later use during GC.  */
+        case R_NIOS2_GNU_VTINHERIT:
+	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+            return FALSE;
+          break;
+
+          /* This relocation describes which C++ vtable entries are actually
+             used.  Record for later use during GC.  */
+	case R_NIOS2_GNU_VTENTRY:
+          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return FALSE;
+          break;
+
+	case R_NIOS2_BFD_RELOC_32:
+	case R_NIOS2_CALL26:
+	case R_NIOS2_HIADJ16:
+	case R_NIOS2_LO16:
+
+	  if (h != NULL)
+	    {
+	      /* If this reloc is in a read-only section, we might
+                   need a copy reloc.  We can't check reliably at this
+                   stage whether the section is read-only, as input
+                   sections have not yet been mapped to output sections.
+                   Tentatively set the flag for now, and correct in
+                   adjust_dynamic_symbol.  */
+	      if (!info->shared)
+		h->non_got_ref = 1;
+
+	      /* Make sure a plt entry is created for this symbol if it
+		 turns out to be a function defined by a dynamic object.  */
+	      h->plt.refcount++;
+
+	      if (r_type == R_NIOS2_CALL26)
+		h->needs_plt = 1;
+	    }
+
+	  /* If we are creating a shared library, we need to copy the
+	     reloc into the shared library.  */
+	  if (info->shared
+	      && (sec->flags & SEC_ALLOC) != 0
+	      && (r_type == R_NIOS2_BFD_RELOC_32
+		  || (h != NULL && ! h->needs_plt
+		      && (! info->symbolic || ! h->def_regular))))
+	    {
+	      struct elf32_nios2_dyn_relocs *p;
+	      struct elf32_nios2_dyn_relocs **head;
+
+	      /* When creating a shared object, we must copy these
+		 reloc types into the output file.  We create a reloc
+		 section in dynobj and make room for this reloc.  */
+	      if (sreloc == NULL)
+		{
+		  const char *name;
+
+		  name = (bfd_elf_string_from_elf_section
+			  (abfd,
+			   elf_elfheader (abfd)->e_shstrndx,
+			   _bfd_elf_single_rel_hdr (sec)->sh_name));
+		  if (name == NULL)
+		    return FALSE;
+
+		  BFD_ASSERT (CONST_STRNEQ (name, ".rela")
+			      && (strcmp (bfd_get_section_name (abfd, sec),
+					 name + 5)
+				  == 0));
+
+		  sreloc = bfd_get_section_by_name (dynobj, name);
+		  if (sreloc == NULL)
+		    {
+		      sreloc = bfd_make_section_with_flags
+			(dynobj,
+			 name,
+			 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+			  | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY));
+		      if (sreloc == NULL
+			  || !bfd_set_section_alignment (dynobj, sreloc, 2))
+			return FALSE;
+		    }
+		  elf_section_data (sec)->sreloc = sreloc;
+		}
+
+              /* If this is a global symbol, we count the number of
+                 relocations we need for this symbol.  */
+              if (h != NULL)
+                head = &((struct elf32_nios2_link_hash_entry *) h)->dyn_relocs;
+              else
+                {
+                  /* Track dynamic relocs needed for local syms too.
+                     We really need local syms available to do this
+                     easily.  Oh well.  */
+
+                  asection *s;
+                  void *vpp;
+		  Elf_Internal_Sym *isym;
+
+		  isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+						abfd, r_symndx);
+		  if (isym == NULL)
+                    return FALSE;
+
+		  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+		  if (s == NULL)
+		    s = sec;
+
+                  vpp = &elf_section_data (s)->local_dynrel;
+                  head = (struct elf32_nios2_dyn_relocs **) vpp;
+                }
+
+              p = *head;
+              if (p == NULL || p->sec != sec)
+                {
+                  bfd_size_type amt = sizeof *p;
+                  p = ((struct elf32_nios2_dyn_relocs *)
+                       bfd_alloc (htab->root.dynobj, amt));
+                  if (p == NULL)
+                    return FALSE;
+                  p->next = *head;
+                  *head = p;
+                  p->sec = sec;
+                  p->count = 0;
+                  p->pc_count = 0;
+                }
+
+              p->count += 1;
+
+	    }
+	  break;
+	}
+    }
+
+  return TRUE;
+}
+
+
+/* Implement elf_backend_gc_mark_hook:
+   Return the section that should be marked against GC for a given
+   relocation.  */
+static asection *
+nios2_elf32_gc_mark_hook (asection *sec,
+			  struct bfd_link_info *info ATTRIBUTE_UNUSED,
+			  Elf_Internal_Rela *rel,
+			  struct elf_link_hash_entry *h,
+			  Elf_Internal_Sym *sym)
+{
+  if (h != NULL)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_NIOS2_GNU_VTINHERIT:
+      case R_NIOS2_GNU_VTENTRY:
+	return NULL;
+      }
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+
+/* Implement elf_backend_gc_sweep_hook:
+   Update the got entry reference counts for the section being removed.  */
+static bfd_boolean
+nios2_elf32_gc_sweep_hook (bfd *abfd,
+	  	  	   struct bfd_link_info *info,
+			   asection *sec,
+			   const Elf_Internal_Rela *relocs)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  bfd *dynobj;
+  asection *sgot;
+  asection *srelgot;
+  struct elf32_nios2_link_hash_table *htab;
+
+  if (info->relocatable)
+    return TRUE;
+
+  htab = elf32_nios2_hash_table (info);
+  sgot = htab->root.sgot;
+  srelgot = htab->root.srelgot;
+
+  elf_section_data (sec)->local_dynrel = NULL;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj == NULL)
+    return TRUE;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h = NULL;
+      int r_type;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx >= symtab_hdr->sh_info)
+	{
+	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	  while (h->root.type == bfd_link_hash_indirect
+		 || h->root.type == bfd_link_hash_warning)
+	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+	}
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      switch (r_type)
+	{
+	case R_NIOS2_GOT16:
+        case R_NIOS2_CALL16:
+	  if (h != NULL)
+	    {
+	      if (h->got.refcount > 0)
+		--h->got.refcount;
+	    }
+	  else if (local_got_refcounts != NULL)
+	    {
+	      if (local_got_refcounts[r_symndx] > 0)
+		--local_got_refcounts[r_symndx];
+	    }
+	  break;
+
+	case R_NIOS2_PCREL_LO:
+	case R_NIOS2_PCREL_HA:
+	case R_NIOS2_BFD_RELOC_32:
+	case R_NIOS2_CALL26:
+	  if (h != NULL)
+	    {
+              struct elf32_nios2_link_hash_entry *eh;
+              struct elf32_nios2_dyn_relocs **pp;
+              struct elf32_nios2_dyn_relocs *p;
+
+              eh = (struct elf32_nios2_link_hash_entry *) h;
+
+	      if (h->plt.refcount > 0)
+		--h->plt.refcount;
+
+	      if (r_type == R_NIOS2_PCREL_LO || r_type == R_NIOS2_PCREL_HA
+		  || r_type == R_NIOS2_BFD_RELOC_32)
+		{
+		  for (pp = &eh->dyn_relocs; (p = *pp) != NULL;
+		       pp = &p->next)
+		    if (p->sec == sec)
+		      {
+			p->count -= 1;
+			if (p->count == 0)
+			  *pp = p->next;
+			break;
+		      }
+		}
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+    }
+
+  return TRUE;
+}
+
+/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC.  */
+static void
+nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value)
+{
+  bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset);
+
+  BFD_ASSERT(value <= 0xffff);
+
+  bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6),
+              sec->contents + offset);
+}
+
+/* Install COUNT 32-bit values DATA starting at offset OFFSET into
+   section SEC. */
+static void
+nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset,
+			  int count)
+{
+  while (count--)
+    {
+      bfd_put_32 (sec->owner, *data, sec->contents + offset);
+      offset += 4;
+      ++data;
+    }
+}
+
+/* Implement elf_backend_finish_dynamic_symbols:
+   Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+static bfd_boolean
+nios2_elf32_finish_dynamic_symbol (bfd *output_bfd,
+				   struct bfd_link_info *info,
+				   struct elf_link_hash_entry *h,
+				   Elf_Internal_Sym *sym)
+{
+  struct elf32_nios2_link_hash_table *htab;
+  struct elf32_nios2_link_hash_entry *eh
+    = (struct elf32_nios2_link_hash_entry *)h;
+  bfd *dynobj;
+  int use_plt;
+
+  htab = elf32_nios2_hash_table (info);
+  dynobj = elf_hash_table (info)->dynobj;
+
+  if (h->plt.offset != (bfd_vma) -1)
+    {
+      asection *splt;
+      asection *sgotplt;
+      asection *srela;
+      bfd_vma plt_index;
+      bfd_vma got_offset;
+      Elf_Internal_Rela rela;
+      bfd_byte *loc;
+      bfd_vma got_address;
+
+      /* This symbol has an entry in the procedure linkage table.  Set
+	 it up.  */
+      BFD_ASSERT (h->dynindx != -1);
+      splt = htab->root.splt;
+      sgotplt = htab->root.sgotplt;
+      srela = htab->root.srelplt;
+      BFD_ASSERT (splt != NULL && sgotplt != NULL && srela != NULL);
+
+      /* Emit the PLT entry.  */
+      if (info->shared)
+        {
+	  nios2_elf32_install_data (splt, nios2_so_plt_entry, h->plt.offset,
+				    3);
+          plt_index = (h->plt.offset - 24) / 12;
+          got_offset = (plt_index + 3) * 4;
+          nios2_elf32_install_imm16 (splt, h->plt.offset,
+                                     hiadj(plt_index * 4));
+          nios2_elf32_install_imm16 (splt, h->plt.offset + 4,
+                                     (plt_index * 4) & 0xffff);
+          nios2_elf32_install_imm16 (splt, h->plt.offset + 8,
+                                     0xfff4 - h->plt.offset);
+	  got_address = (sgotplt->output_section->vma + sgotplt->output_offset
+			 + got_offset);
+
+	  /* Fill in the entry in the global offset table.  There are no
+	     res_n slots for a shared object PLT, instead the .got.plt entries
+	     point to the PLT entries.  */
+	  bfd_put_32 (output_bfd,
+		      splt->output_section->vma + splt->output_offset
+		      + h->plt.offset, sgotplt->contents + got_offset);
+        }
+      else
+        {
+          plt_index = (h->plt.offset - 28 - htab->res_n_size) / 12;
+          got_offset = (plt_index + 3) * 4;
+
+	  nios2_elf32_install_data (splt, nios2_plt_entry, h->plt.offset, 3);
+          got_address = (sgotplt->output_section->vma + sgotplt->output_offset
+                         + got_offset);
+          nios2_elf32_install_imm16 (splt, h->plt.offset, hiadj(got_address));
+          nios2_elf32_install_imm16 (splt, h->plt.offset + 4,
+                                     got_address & 0xffff);
+
+	  /* Fill in the entry in the global offset table.  */
+	  bfd_put_32 (output_bfd,
+		      splt->output_section->vma + splt->output_offset
+		      + plt_index * 4, sgotplt->contents + got_offset);
+        }
+
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_offset = got_address;
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_JUMP_SLOT);
+      rela.r_addend = 0;
+      loc = srela->contents + plt_index * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+
+      if (!h->def_regular)
+	{
+	  /* Mark the symbol as undefined, rather than as defined in
+	     the .plt section.  Leave the value alone.  */
+	  sym->st_shndx = SHN_UNDEF;
+          /* If the symbol is weak, we do need to clear the value.
+             Otherwise, the PLT entry would provide a definition for
+             the symbol even if the symbol wasn't defined anywhere,
+             and so the symbol would never be NULL.  */
+          if (!h->ref_regular_nonweak)
+            sym->st_value = 0;
+	}
+    }
+
+  use_plt = (eh->got_types_used == CALL16_USED
+	     && h->plt.offset != (bfd_vma) -1);
+
+  if (!use_plt && h->got.offset != (bfd_vma) -1
+      && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_GD) == 0
+      && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_IE) == 0)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+      bfd_byte *loc;
+      bfd_vma offset;
+
+      /* This symbol has an entry in the global offset table.  Set it
+	 up.  */
+      sgot = htab->root.sgot;
+      srela = htab->root.srelgot;
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      offset = (h->got.offset & ~(bfd_vma) 1);
+      rela.r_offset = (sgot->output_section->vma
+		       + sgot->output_offset + offset);
+
+      /* If this is a -Bsymbolic link, and the symbol is defined
+	 locally, we just want to emit a RELATIVE reloc.  Likewise if
+	 the symbol was forced to be local because of a version file.
+	 The entry in the global offset table will already have been
+	 initialized in the relocate_section function.  */
+
+      if (info->shared && SYMBOL_REFERENCES_LOCAL (info, h))
+	{
+	  rela.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE);
+	  rela.r_addend = bfd_get_signed_32 (output_bfd,
+					     (sgot->contents + offset));
+	  bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
+	}
+      else
+	{
+	  bfd_put_32 (output_bfd, (bfd_vma) 0,
+		      sgot->contents + offset);
+	  rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_GLOB_DAT);
+	  rela.r_addend = 0;
+	}
+
+      loc = srela->contents;
+      loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+    }
+
+  if (use_plt && h->got.offset != (bfd_vma) -1)
+    {
+      bfd_vma offset = (h->got.offset & ~(bfd_vma) 1);
+      asection *sgot = htab->root.sgot;
+      asection *splt = htab->root.splt;
+      bfd_put_32 (output_bfd, (splt->output_section->vma + splt->output_offset
+			       + h->plt.offset),
+		  sgot->contents + offset);
+    }
+
+  if (h->needs_copy)
+    {
+      asection *s;
+      Elf_Internal_Rela rela;
+      bfd_byte *loc;
+
+      /* This symbol needs a copy reloc.  Set it up.  */
+      BFD_ASSERT (h->dynindx != -1
+		  && (h->root.type == bfd_link_hash_defined
+		      || h->root.type == bfd_link_hash_defweak));
+
+      s = bfd_get_section_by_name (h->root.u.def.section->owner,
+				   ".rela.bss");
+      BFD_ASSERT (s != NULL);
+
+      rela.r_offset = (h->root.u.def.value
+		       + h->root.u.def.section->output_section->vma
+		       + h->root.u.def.section->output_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_COPY);
+      rela.r_addend = 0;
+      loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+    }
+
+  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || h == elf_hash_table (info)->hgot)
+    sym->st_shndx = SHN_ABS;
+
+  return TRUE;
+}
+
+/* Implement elf_backend_finish_dynamic_sections.  */
+static bfd_boolean
+nios2_elf32_finish_dynamic_sections (bfd *output_bfd,
+				     struct bfd_link_info *info)
+{
+  bfd *dynobj;
+  asection *sgotplt;
+  asection *sdyn;
+  struct elf32_nios2_link_hash_table *htab;
+
+  htab = elf32_nios2_hash_table (info);
+  dynobj = elf_hash_table (info)->dynobj;
+  sgotplt = htab->root.sgotplt;
+  BFD_ASSERT (sgotplt != NULL);
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      asection *splt;
+      Elf32_External_Dyn *dyncon, *dynconend;
+
+      splt = htab->root.splt;
+      BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+      dyncon = (Elf32_External_Dyn *) sdyn->contents;
+      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
+      for (; dyncon < dynconend; dyncon++)
+	{
+	  Elf_Internal_Dyn dyn;
+	  const char *name;
+	  asection *s;
+
+	  bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+	  switch (dyn.d_tag)
+	    {
+	    default:
+	      break;
+
+	    case DT_PLTGOT:
+	      name = ".got";
+	      goto get_vma;
+	    case DT_JMPREL:
+	      name = ".rela.plt";
+	    get_vma:
+	      s = bfd_get_section_by_name (output_bfd, name);
+	      BFD_ASSERT (s != NULL);
+	      dyn.d_un.d_ptr = s->vma;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+
+	    case DT_PLTRELSZ:
+	      s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+	      BFD_ASSERT (s != NULL);
+	      dyn.d_un.d_val = s->size;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+
+	    case DT_RELASZ:
+	      /* The procedure linkage table relocs (DT_JMPREL) should
+		 not be included in the overall relocs (DT_RELA).
+		 Therefore, we override the DT_RELASZ entry here to
+		 make it not include the JMPREL relocs.  Since the
+		 linker script arranges for .rela.plt to follow all
+		 other relocation sections, we don't have to worry
+		 about changing the DT_RELA entry.  */
+	      s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+	      if (s != NULL)
+		dyn.d_un.d_val -= s->size;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+
+	    case DT_NIOS2_GP:
+	      s = bfd_get_section_by_name (output_bfd, ".got");
+	      BFD_ASSERT (s != NULL);
+	      dyn.d_un.d_ptr = s->vma + 0x7ff0;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+	    }
+	}
+
+      /* Fill in the first entry in the procedure linkage table.  */
+      if (splt->size > 0)
+	{
+          bfd_vma got_address = (sgotplt->output_section->vma
+				 + sgotplt->output_offset);
+          if (info->shared)
+            {
+              bfd_vma corrected = got_address - (splt->output_section->vma
+						 + splt->output_offset + 4);
+	      nios2_elf32_install_data (splt, nios2_so_plt0_entry, 0, 6);
+              nios2_elf32_install_imm16 (splt, 4, hiadj (corrected));
+              nios2_elf32_install_imm16 (splt, 12, (corrected & 0xffff) + 4);
+              nios2_elf32_install_imm16 (splt, 16, (corrected & 0xffff) + 8);
+
+   	      elf_section_data (splt->output_section)->this_hdr.sh_entsize
+   	        = 24;
+            }
+          else
+            {
+	      /* Divide by 4 here, not 3 because we already corrected for the
+		 res_N branches.  */
+              bfd_vma res_size = (splt->size - 28) / 4;
+              bfd_vma res_start = (splt->output_section->vma
+				   + splt->output_offset);
+              bfd_vma res_offset;
+
+              for (res_offset = 0; res_offset < res_size; res_offset += 4)
+                bfd_put_32 (output_bfd,
+			    6 | ((res_size - (res_offset + 4)) << 6),
+                            splt->contents + res_offset);
+
+	      nios2_elf32_install_data (splt, nios2_plt0_entry, res_size, 7);
+              nios2_elf32_install_imm16 (splt, res_size, hiadj (res_start));
+              nios2_elf32_install_imm16 (splt, res_size + 4,
+					 res_start & 0xffff);
+              nios2_elf32_install_imm16 (splt, res_size + 12,
+					 hiadj (got_address));
+              nios2_elf32_install_imm16 (splt, res_size + 16,
+					 (got_address & 0xffff) + 4);
+              nios2_elf32_install_imm16 (splt, res_size + 20,
+					 (got_address & 0xffff) + 8);
+
+   	      elf_section_data (splt->output_section)->this_hdr.sh_entsize
+	        = 28 + res_size;
+            }
+	}
+    }
+  /* Fill in the first three entries in the global offset table.  */
+  if (sgotplt->size > 0)
+    {
+      if (sdyn == NULL)
+	bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents);
+      else
+	bfd_put_32 (output_bfd,
+		    sdyn->output_section->vma + sdyn->output_offset,
+		    sgotplt->contents);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8);
+    }
+
+  elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4;
+
+  return TRUE;
+}
+
+/* Implement elf_backend_adjust_dynamic_symbol:
+   Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+static bfd_boolean
+nios2_elf32_adjust_dynamic_symbol (struct bfd_link_info *info,
+				   struct elf_link_hash_entry *h)
+{
+  struct elf32_nios2_link_hash_table *htab;
+  bfd *dynobj;
+  asection *s;
+  unsigned align2;
+
+  htab = elf32_nios2_hash_table (info);
+  dynobj = elf_hash_table (info)->dynobj;
+
+  /* Make sure we know what is going on here.  */
+  BFD_ASSERT (dynobj != NULL
+              && (h->needs_plt
+                  || h->u.weakdef != NULL
+                  || (h->def_dynamic
+                      && h->ref_regular
+                      && !h->def_regular)));
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC || h->needs_plt)
+    {
+      if (h->plt.refcount <= 0
+          || SYMBOL_CALLS_LOCAL (info, h)
+          || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+              && h->root.type == bfd_link_hash_undefweak))
+	{
+	  /* This case can occur if we saw a PLT reloc in an input
+             file, but the symbol was never referred to by a dynamic
+             object, or if all references were garbage collected.  In
+             such a case, we don't actually need to build a procedure
+             linkage table, and we can just do a PCREL reloc instead.  */
+          h->plt.offset = (bfd_vma) -1;
+          h->needs_plt = 0;
+        }
+
+      return TRUE;
+    }
+
+  /* Reinitialize the plt offset now that it is not used as a reference
+     count any more.  */
+  h->plt.offset = (bfd_vma) -1;
+
+  /* If this is a weak symbol, and there is a real definition, the
+     processor independent code will have arranged for us to see the
+     real definition first, and we can just use the same value.  */
+  if (h->u.weakdef != NULL)
+    {
+      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->u.weakdef->root.u.def.section;
+      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      return TRUE;
+    }
+
+  /* If there are no non-GOT references, we do not need a copy
+     relocation.  */
+  if (!h->non_got_ref)
+    return TRUE;
+
+  /* This is a reference to a symbol defined by a dynamic object which
+     is not a function.
+     If we are creating a shared library, we must presume that the
+     only references to the symbol are via the global offset table.
+     For such cases we need not do anything here; the relocations will
+     be handled correctly by relocate_section.  */
+  if (info->shared)
+    return TRUE;
+
+  if (h->size == 0)
+    {
+      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+                             h->root.root.string);
+      return TRUE;
+    }
+
+  /* We must allocate the symbol in our .dynbss section, which will
+     become part of the .bss section of the executable.  There will be
+     an entry for this symbol in the .dynsym section.  The dynamic
+     object will contain position independent code, so all references
+     from the dynamic object to this symbol will go through the global
+     offset table.  The dynamic linker will use the .dynsym entry to
+     determine the address it must put in the global offset table, so
+     both the dynamic object and the regular object will refer to the
+     same memory location for the variable.  */
+  s = htab->sdynbss;
+  BFD_ASSERT (s != NULL);
+
+  /* We must generate a R_NIOS2_COPY reloc to tell the dynamic linker to
+     copy the initial value out of the dynamic object and into the
+     runtime process image.  We need to remember the offset into the
+     .rela.bss section we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+    {
+      asection *srel;
+
+      srel = htab->srelbss;
+      BFD_ASSERT (srel != NULL);
+      srel->size += sizeof (Elf32_External_Rela);
+      h->needs_copy = 1;
+    }
+
+  align2 = bfd_log2 (h->size);
+  if (align2 > h->root.u.def.section->alignment_power)
+    align2 = h->root.u.def.section->alignment_power;
+
+  /* Align dynbss.  */
+  s->size = BFD_ALIGN (s->size, (bfd_size_type)1 << align2);
+  if (align2 > bfd_get_section_alignment (dynobj, s)
+      && !bfd_set_section_alignment (dynobj, s, align2))
+    return FALSE;
+
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->size;
+
+  /* Increment the section size to make room for the symbol.  */
+  s->size += h->size;
+
+  return TRUE;
+}
+
+/* Worker function for nios2_elf32_size_dynamic_sections.  */
+static bfd_boolean
+adjust_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
+{
+  struct bfd_link_info *info;
+  struct elf32_nios2_link_hash_table *htab;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    /* When warning symbols are created, they **replace** the "real"
+       entry in the hash table, thus we never get to see the real
+       symbol in a hash traversal.  So look at it now.  */
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  info = (struct bfd_link_info *) inf;
+  htab = elf32_nios2_hash_table (info);
+
+  if (h->plt.offset != (bfd_vma)-1)
+    h->plt.offset += htab->res_n_size;
+  if (htab->root.splt == h->root.u.def.section)
+    h->root.u.def.value += htab->res_n_size;
+
+  return TRUE;
+}
+
+/* Another worker function for nios2_elf32_size_dynamic_sections.
+   Allocate space in .plt, .got and associated reloc sections for
+   dynamic relocs.  */
+static bfd_boolean
+allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
+{
+  struct bfd_link_info *info;
+  struct elf32_nios2_link_hash_table *htab;
+  struct elf32_nios2_link_hash_entry *eh;
+  struct elf32_nios2_dyn_relocs *p;
+  int use_plt;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    /* When warning symbols are created, they **replace** the "real"
+       entry in the hash table, thus we never get to see the real
+       symbol in a hash traversal.  So look at it now.  */
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  info = (struct bfd_link_info *) inf;
+  htab = elf32_nios2_hash_table (info);
+
+  if (htab->root.dynamic_sections_created
+      && h->plt.refcount > 0)
+    {
+      /* Make sure this symbol is output as a dynamic symbol.
+         Undefined weak syms won't yet be marked as dynamic.  */
+      if (h->dynindx == -1
+          && !h->forced_local
+	  && !bfd_elf_link_record_dynamic_symbol (info, h))
+	return FALSE;
+
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+        {
+          asection *s = htab->root.splt;
+
+          /* Allocate room for the header.  */
+          if (s->size == 0)
+            {
+	      if (info->shared)
+		s->size = 24;
+	      else
+		s->size = 28;
+            }
+
+	  h->plt.offset = s->size;
+
+          /* If this symbol is not defined in a regular file, and we are
+             not generating a shared library, then set the symbol to this
+             location in the .plt.  This is required to make function
+             pointers compare as equal between the normal executable and
+             the shared library.  */
+          if (! info->shared
+              && !h->def_regular)
+            {
+	      h->root.u.def.section = s;
+              h->root.u.def.value = h->plt.offset;
+	    }
+
+          /* Make room for this entry.  */
+          s->size += 12;
+
+	  /* We also need to make an entry in the .rela.plt section.  */
+          htab->root.srelplt->size += sizeof (Elf32_External_Rela);
+
+	  /* And the .got.plt section.  */
+	  htab->root.sgotplt->size += 4;
+	}
+      else
+        {
+          h->plt.offset = (bfd_vma) -1;
+          h->needs_plt = 0;
+	}
+    }
+  else
+    {
+      h->plt.offset = (bfd_vma) -1;
+      h->needs_plt = 0;
+    }
+
+  eh = (struct elf32_nios2_link_hash_entry *) h;
+  use_plt = (eh->got_types_used == CALL16_USED
+	     && h->plt.offset != (bfd_vma) -1);
+
+  if (h->got.refcount > 0)
+    {
+      asection *s;
+      bfd_boolean dyn;
+      int tls_type = eh->tls_type;
+      int indx;
+
+      /* Make sure this symbol is output as a dynamic symbol.
+         Undefined weak syms won't yet be marked as dynamic.  */
+      if (h->dynindx == -1
+	  && !h->forced_local
+	  && !bfd_elf_link_record_dynamic_symbol (info, h))
+	return FALSE;
+
+      s = htab->root.sgot;
+      h->got.offset = s->size;
+
+      if (tls_type == GOT_UNKNOWN)
+	abort ();
+
+      if (tls_type == GOT_NORMAL)
+	/* Non-TLS symbols need one GOT slot.  */
+	s->size += 4;
+      else
+	{
+	  if (tls_type & GOT_TLS_GD)
+	    /* R_NIOS2_TLS_GD16 needs 2 consecutive GOT slots.  */
+	    s->size += 8;
+	  if (tls_type & GOT_TLS_IE)
+	    /* R_NIOS2_TLS_IE16 needs one GOT slot.  */
+	    s->size += 4;
+	}
+
+      dyn = htab->root.dynamic_sections_created;
+
+      indx = 0;
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+	  && (!info->shared
+	      || !SYMBOL_REFERENCES_LOCAL (info, h)))
+	indx = h->dynindx;
+
+      if (tls_type != GOT_NORMAL
+	  && (info->shared || indx != 0)
+	  && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+	      || h->root.type != bfd_link_hash_undefweak))
+	{
+	  if (tls_type & GOT_TLS_IE)
+	    htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+
+	  if (tls_type & GOT_TLS_GD)
+	    htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+
+	  if ((tls_type & GOT_TLS_GD) && indx != 0)
+	    htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+	}
+      else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+		|| h->root.type != bfd_link_hash_undefweak)
+	       && !use_plt
+	       && (info->shared
+		   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+	htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+    }
+  else
+    h->got.offset = (bfd_vma) -1;
+
+  if (eh->dyn_relocs == NULL)
+    return TRUE;
+
+  /* In the shared -Bsymbolic case, discard space allocated for
+     dynamic pc-relative relocs against symbols which turn out to be
+     defined in regular objects.  For the normal shared case, discard
+     space for pc-relative relocs that have become local due to symbol
+     visibility changes.  */
+
+  if (info->shared)
+    {
+      if (h->def_regular
+          && (h->forced_local || info->symbolic))
+        {
+          struct elf32_nios2_dyn_relocs **pp;
+
+          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+            {
+              p->count -= p->pc_count;
+              p->pc_count = 0;
+              if (p->count == 0)
+		*pp = p->next;
+              else
+                pp = &p->next;
+            }
+        }
+
+      /* Also discard relocs on undefined weak syms with non-default
+         visibility.  */
+      if (eh->dyn_relocs != NULL
+          && h->root.type == bfd_link_hash_undefweak)
+	{
+          if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+            eh->dyn_relocs = NULL;
+
+          /* Make sure undefined weak symbols are output as a dynamic
+             symbol in PIEs.  */
+          else if (h->dynindx == -1
+		   && !h->forced_local
+		   && !bfd_elf_link_record_dynamic_symbol (info, h))
+	    return FALSE;
+        }
+    }
+  else
+    {
+      /* For the non-shared case, discard space for relocs against
+         symbols which turn out to need copy relocs or are not
+         dynamic.  */
+
+      if (!h->non_got_ref
+	  && ((h->def_dynamic && !h->def_regular)
+              || (htab->root.dynamic_sections_created
+                  && (h->root.type == bfd_link_hash_undefweak
+                      || h->root.type == bfd_link_hash_undefined))))
+        {
+          /* Make sure this symbol is output as a dynamic symbol.
+             Undefined weak syms won't yet be marked as dynamic.  */
+          if (h->dynindx == -1
+	      && !h->forced_local
+	      && !bfd_elf_link_record_dynamic_symbol (info, h))
+	    return FALSE;
+
+          /* If that succeeded, we know we'll be keeping all the
+             relocs.  */
+	  if (h->dynindx != -1)
+            goto keep;
+	}
+
+      eh->dyn_relocs = NULL;
+
+    keep: ;
+    }
+
+  /* Finally, allocate space.  */
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *sreloc = elf_section_data (p->sec)->sreloc;
+      sreloc->size += p->count * sizeof (Elf32_External_Rela);
+    }
+
+  return TRUE;
+}
+
+/* Implement elf_backend_size_dynamic_sections:
+   Set the sizes of the dynamic sections.  */
+static bfd_boolean
+nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+                                   struct bfd_link_info *info)
+{
+  bfd *dynobj;
+  asection *s;
+  bfd_boolean plt;
+  bfd_boolean got;
+  bfd_boolean relocs;
+  bfd *ibfd;
+  struct elf32_nios2_link_hash_table *htab;
+
+  htab = elf32_nios2_hash_table (info);
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  htab->res_n_size = 0;
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (info->executable)
+	{
+	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  BFD_ASSERT (s != NULL);
+	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+	}
+    }
+  else
+    {
+      /* We may have created entries in the .rela.got section.
+	 However, if we are not creating the dynamic sections, we will
+	 not actually use these entries.  Reset the size of .rela.got,
+	 which will cause it to get stripped from the output file
+	 below.  */
+      s = htab->root.srelgot;
+      if (s != NULL)
+	s->size = 0;
+    }
+
+  /* Set up .got offsets for local syms, and space for local dynamic
+     relocs.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      bfd_signed_vma *local_got;
+      bfd_signed_vma *end_local_got;
+      char *local_tls_type;
+      bfd_size_type locsymcount;
+      Elf_Internal_Shdr *symtab_hdr;
+      asection *srel;
+
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+        continue;
+
+      for (s = ibfd->sections; s != NULL; s = s->next)
+        {
+          struct elf32_nios2_dyn_relocs *p;
+
+          for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
+            {
+              if (!bfd_is_abs_section (p->sec)
+                  && bfd_is_abs_section (p->sec->output_section))
+                {
+                  /* Input section has been discarded, either because
+                     it is a copy of a linkonce section or due to
+                     linker script /DISCARD/, so we'll be discarding
+                     the relocs too.  */
+                }
+	      else if (p->count != 0)
+                {
+                  srel = elf_section_data (p->sec)->sreloc;
+                  srel->size += p->count * sizeof (Elf32_External_Rela);
+                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+                    info->flags |= DF_TEXTREL;
+                }
+            }
+	}
+
+      local_got = elf_local_got_refcounts (ibfd);
+      if (!local_got)
+        continue;
+
+      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      locsymcount = symtab_hdr->sh_info;
+      end_local_got = local_got + locsymcount;
+      local_tls_type = elf32_nios2_local_got_tls_type (ibfd);
+      s = htab->root.sgot;
+      srel = htab->root.srelgot;
+      for (; local_got < end_local_got; ++local_got, ++local_tls_type)
+        {
+          if (*local_got > 0)
+            {
+              *local_got = s->size;
+              if (*local_tls_type & GOT_TLS_GD)
+                /* TLS_GD relocs need an 8-byte structure in the GOT.  */
+                s->size += 8;
+              if (*local_tls_type & GOT_TLS_IE)
+                s->size += 4;
+              if (*local_tls_type == GOT_NORMAL)
+                s->size += 4;
+
+              if (info->shared || *local_tls_type == GOT_TLS_GD)
+                srel->size += sizeof (Elf32_External_Rela);
+            }
+          else
+            *local_got = (bfd_vma) -1;
+        }
+    }
+
+  if (htab->tls_ldm_got.refcount > 0)
+    {
+      /* Allocate two GOT entries and one dynamic relocation (if necessary)
+         for R_NIOS2_TLS_LDM16 relocations.  */
+      htab->tls_ldm_got.offset = htab->root.sgot->size;
+      htab->root.sgot->size += 8;
+      if (info->shared)
+        htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+    }
+  else
+    htab->tls_ldm_got.offset = -1;
+
+  /* Allocate global sym .plt and .got entries, and space for global
+     sym dynamic relocs.  */
+  elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = FALSE;
+  got = FALSE;
+  relocs = FALSE;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+	continue;
+
+      /* It's OK to base decisions on the section name, because none
+	 of the dynobj section names depend upon the input files.  */
+      name = bfd_get_section_name (dynobj, s);
+
+      if (strcmp (name, ".plt") == 0)
+	{
+	  /* Remember whether there is a PLT.  */
+	  plt = s->size != 0;
+
+          /* Correct for the number of res_N branches.  */
+          if (plt && !info->shared)
+	    {
+	      htab->res_n_size = (s->size-28) / 3;
+	      s->size += htab->res_n_size;
+	    }
+	}
+      else if (CONST_STRNEQ (name, ".rela"))
+	{
+	  if (s->size != 0)
+	    {
+	      relocs = TRUE;
+
+	      /* We use the reloc_count field as a counter if we need
+		 to copy relocs into the output file.  */
+	      s->reloc_count = 0;
+	    }
+	}
+      else if (CONST_STRNEQ (name, ".got"))
+	got = s->size != 0;
+      else if (strcmp (name, ".dynbss") != 0)
+	/* It's not one of our sections, so don't allocate space.  */
+	continue;
+
+      if (s->size == 0)
+	{
+	  /* If we don't need this section, strip it from the
+	     output file.  This is mostly to handle .rela.bss and
+	     .rela.plt.  We must create both sections in
+	     create_dynamic_sections, because they must be created
+	     before the linker maps input sections to output
+	     sections.  The linker does that before
+	     adjust_dynamic_symbol is called, and it is that
+	     function which decides whether anything needs to go
+	     into these sections.  */
+	  s->flags |= SEC_EXCLUDE;
+	  continue;
+	}
+
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
+	continue;
+
+      /* Allocate memory for the section contents.  */
+      /* FIXME: This should be a call to bfd_alloc not bfd_zalloc.
+	 Unused entries should be reclaimed before the section's contents
+	 are written out, but at the moment this does not happen.  Thus in
+	 order to prevent writing out garbage, we initialize the section's
+	 contents to zero.  */
+      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+      if (s->contents == NULL)
+	return FALSE;
+    }
+
+  /* Adjust dynamic symbols that point to the plt to account for the
+     now-known number of resN slots.  */
+  if (htab->res_n_size)
+    elf_link_hash_traverse (& htab->root, adjust_dynrelocs, info);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Add some entries to the .dynamic section.  We fill in the
+	 values later, in elf_nios2_finish_dynamic_sections, but we
+	 must add the entries now so that we get the correct size for
+	 the .dynamic section.  The DT_DEBUG entry is filled in by the
+	 dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+      if (!info->shared && !add_dynamic_entry (DT_DEBUG, 0))
+	return FALSE;
+
+      if (got && !add_dynamic_entry (DT_PLTGOT, 0))
+	return FALSE;
+
+      if (plt
+	  && (!add_dynamic_entry (DT_PLTRELSZ, 0)
+	      || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+	      || !add_dynamic_entry (DT_JMPREL, 0)))
+	return FALSE;
+
+      if (relocs
+	  && (!add_dynamic_entry (DT_RELA, 0)
+	      || !add_dynamic_entry (DT_RELASZ, 0)
+	      || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))))
+	return FALSE;
+
+      if (!info->shared && !add_dynamic_entry (DT_NIOS2_GP, 0))
+	return FALSE;
+
+      if ((info->flags & DF_TEXTREL) != 0
+	  && !add_dynamic_entry (DT_TEXTREL, 0))
+	return FALSE;
+    }
+#undef add_dynamic_entry
+
+  return TRUE;
+}
+
+/* Implement bfd_elf32_bfd_link_hash_table_create.  */
+static struct bfd_link_hash_table *
+nios2_elf32_link_hash_table_create (bfd *abfd)
+{
+  struct elf32_nios2_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf32_nios2_link_hash_table);
+
+  ret = bfd_malloc (amt);
+  if (ret == NULL)
+    return NULL;
+
+  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+				      link_hash_newfunc,
+				      sizeof (struct
+					      elf32_nios2_link_hash_entry),
+				      NIOS2_ELF_DATA))
+    {
+      free (ret);
+      return NULL;
+    }
+
+  ret->sdynbss = NULL;
+  ret->srelbss = NULL;
+  ret->sbss = NULL;
+  ret->tls_ldm_got.refcount = 0;
+  ret->sym_cache.abfd = NULL;
+  return &ret->root.root;
+}
+
+/* Implement elf_backend_reloc_type_class.  */
+static enum elf_reloc_type_class
+nios2_elf32_reloc_type_class (const Elf_Internal_Rela *rela)
+{
+  switch ((int) ELF32_R_TYPE (rela->r_info))
+    {
+    case R_NIOS2_RELATIVE:
+      return reloc_class_relative;
+    case R_NIOS2_JUMP_SLOT:
+      return reloc_class_plt;
+    case R_NIOS2_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+
+/* Return 1 if target is one of ours.  */
+static bfd_boolean
+is_nios2_elf_target (const struct bfd_target *targ)
+{
+  return (targ == &bfd_elf32_littlenios2_vec
+	  || targ == &bfd_elf32_bignios2_vec);
+}
+
+/* Implement elf_backend_add_symbol_hook.
+   This hook is called by the linker when adding symbols from an object
+   file.  We use it to put .comm items in .sbss, and not .bss.  */
+static bfd_boolean
+nios2_elf_add_symbol_hook (bfd *abfd,
+                           struct bfd_link_info *info,
+                           Elf_Internal_Sym *sym,
+                           const char **namep ATTRIBUTE_UNUSED,
+                           flagword *flagsp ATTRIBUTE_UNUSED,
+                           asection **secp,
+                           bfd_vma *valp)
+{
+  bfd *dynobj;
+
+  if (sym->st_shndx == SHN_COMMON
+      && !info->relocatable
+      && sym->st_size <= elf_gp_size (abfd)
+      && is_nios2_elf_target (info->output_bfd->xvec))
+    {
+      /* Common symbols less than or equal to -G nn bytes are automatically
+         put into .sbss.  */
+      struct elf32_nios2_link_hash_table *htab;
+
+      htab = elf32_nios2_hash_table (info);
+      if (htab->sbss == NULL)
+        {
+          flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
+
+	  dynobj = elf_hash_table (info)->dynobj;
+	  if (!dynobj)
+	    dynobj = abfd;
+
+	  /* ??? Will this section creation clash with .sbss created as
+	     one elf32_nios2_special_sections?
+	     And, more generally, we may not need this anymore since
+	     .sbss is created via elf32_nios2_special_sections.  Same applies
+	     to elf32-ppc.c and, possibly, other targets.  */
+          htab->sbss = bfd_make_section_anyway_with_flags (dynobj, ".sbss",
+                                                           flags);
+          if (htab->sbss == NULL)
+            return FALSE;
+        }
+
+      *secp = htab->sbss;
+      *valp = sym->st_size;
+    }
+
+  return TRUE;
+}
+
+/* Implement elf_backend_can_make_relative_eh_frame:
+   Decide whether to attempt to turn absptr or lsda encodings in
+   shared libraries into pcrel within the given input section.  */
+static bfd_boolean
+nios2_elf32_can_make_relative_eh_frame(bfd *input_bfd ATTRIBUTE_UNUSED,
+				       struct bfd_link_info *info
+				       ATTRIBUTE_UNUSED,
+				       asection *eh_frame_section
+				       ATTRIBUTE_UNUSED)
+{
+  /* We can't use PC-relative encodings in the .eh_frame section.  */
+  return FALSE;
+}
+
+/* Implement elf_backend_special_sections.  */
+const struct bfd_elf_special_section elf32_nios2_special_sections[] =
+{
+  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,
+    SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL },
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,
+    SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL },
+  { NULL,                     0,  0, 0,              0 }
+};
+
+#define ELF_ARCH                        bfd_arch_nios2
+#define ELF_TARGET_ID			NIOS2_ELF_DATA
+#define ELF_MACHINE_CODE                EM_ALTERA_NIOS2
+
+/* The Nios II MMU uses a 4K page size.  */
+
+#define ELF_MAXPAGESIZE                 0x1000
+
+#define bfd_elf32_bfd_link_hash_table_create \
+                                          nios2_elf32_link_hash_table_create
+
+/* Relocation table lookup macros.  */
+
+#define bfd_elf32_bfd_reloc_type_lookup   nios2_elf32_bfd_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup   nios2_elf32_bfd_reloc_name_lookup
+
+/* JUMP_TABLE_LINK macros.  */
+
+/* elf_info_to_howto (using RELA relocations).  */
+
+#define elf_info_to_howto                 nios2_elf32_info_to_howto
+
+/* elf backend functions.  */
+
+#define elf_backend_can_gc_sections	1
+#define elf_backend_can_refcount        1
+#define elf_backend_plt_readonly        1
+#define elf_backend_want_got_plt        1
+#define elf_backend_rela_normal		1
+
+#define elf_backend_relocate_section      nios2_elf32_relocate_section
+#define elf_backend_section_flags         nios2_elf32_section_flags
+#define elf_backend_fake_sections         nios2_elf32_fake_sections
+#define elf_backend_check_relocs	  nios2_elf32_check_relocs
+
+#define elf_backend_gc_mark_hook          nios2_elf32_gc_mark_hook
+#define elf_backend_gc_sweep_hook	  nios2_elf32_gc_sweep_hook
+#define elf_backend_create_dynamic_sections \
+                                          nios2_elf32_create_dynamic_sections
+#define elf_backend_finish_dynamic_symbol nios2_elf32_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+                                          nios2_elf32_finish_dynamic_sections
+#define elf_backend_adjust_dynamic_symbol nios2_elf32_adjust_dynamic_symbol
+#define elf_backend_reloc_type_class      nios2_elf32_reloc_type_class
+#define elf_backend_size_dynamic_sections nios2_elf32_size_dynamic_sections
+#define elf_backend_add_symbol_hook       nios2_elf_add_symbol_hook
+#define elf_backend_copy_indirect_symbol  nios2_elf32_copy_indirect_symbol
+
+#define elf_backend_grok_prstatus         nios2_grok_prstatus
+#define elf_backend_grok_psinfo           nios2_grok_psinfo
+
+#undef elf_backend_can_make_relative_eh_frame
+#define elf_backend_can_make_relative_eh_frame \
+                                          nios2_elf32_can_make_relative_eh_frame
+
+#define elf_backend_special_sections      elf32_nios2_special_sections
+
+#define TARGET_LITTLE_SYM               bfd_elf32_littlenios2_vec
+#define TARGET_LITTLE_NAME              "elf32-littlenios2"
+#define TARGET_BIG_SYM                  bfd_elf32_bignios2_vec
+#define TARGET_BIG_NAME                 "elf32-bignios2"
+
+#define elf_backend_got_header_size	12
+
+#include "elf32-target.h"
Index: include/elf/nios2.h
===================================================================
RCS file: include/elf/nios2.h
diff -N include/elf/nios2.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/elf/nios2.h	22 Jan 2013 18:36:37 -0000
@@ -0,0 +1,91 @@
+/* Altera Nios II ELF support for BFD.
+   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Contributed by Nigel Gray (ngray@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+
+/* This file holds definitions specific to the Altera Nios II ELF ABI.  Note
+   that most of this is not actually implemented by BFD.  */
+
+#ifndef _ELF_NIOS2_H
+#define _ELF_NIOS2_H
+
+#include "elf/reloc-macros.h"
+
+/* The order of these numbers must match the order in
+   the elf_nios2_howto_table_rel table for the lookup
+   function to work properly.  */
+
+START_RELOC_NUMBERS (elf_nios2_reloc_type)
+  RELOC_NUMBER (R_NIOS2_NONE,	  0)
+  RELOC_NUMBER (R_NIOS2_S16,	  1)
+  RELOC_NUMBER (R_NIOS2_U16,	  2)
+  RELOC_NUMBER (R_NIOS2_PCREL16, 3)
+  RELOC_NUMBER (R_NIOS2_CALL26,  4)
+  RELOC_NUMBER (R_NIOS2_IMM5,	  5)
+  RELOC_NUMBER (R_NIOS2_CACHE_OPX, 6)
+  RELOC_NUMBER (R_NIOS2_IMM6,	  7)
+  RELOC_NUMBER (R_NIOS2_IMM8,	  8)
+  RELOC_NUMBER (R_NIOS2_HI16,	  9)
+  RELOC_NUMBER (R_NIOS2_LO16,	  10)
+  RELOC_NUMBER (R_NIOS2_HIADJ16, 11)
+  RELOC_NUMBER (R_NIOS2_BFD_RELOC_32, 12)
+  RELOC_NUMBER (R_NIOS2_BFD_RELOC_16, 13)
+  RELOC_NUMBER (R_NIOS2_BFD_RELOC_8, 14)
+  RELOC_NUMBER (R_NIOS2_GPREL, 15)
+  RELOC_NUMBER (R_NIOS2_GNU_VTINHERIT, 16)
+  RELOC_NUMBER (R_NIOS2_GNU_VTENTRY, 17)
+  RELOC_NUMBER (R_NIOS2_UJMP, 18)
+  RELOC_NUMBER (R_NIOS2_CJMP, 19)
+  RELOC_NUMBER (R_NIOS2_CALLR, 20)
+  RELOC_NUMBER (R_NIOS2_ALIGN, 21)
+  RELOC_NUMBER (R_NIOS2_GOT16, 22)
+  RELOC_NUMBER (R_NIOS2_CALL16, 23)
+  RELOC_NUMBER (R_NIOS2_GOTOFF_LO, 24)
+  RELOC_NUMBER (R_NIOS2_GOTOFF_HA, 25)
+  RELOC_NUMBER (R_NIOS2_PCREL_LO, 26)
+  RELOC_NUMBER (R_NIOS2_PCREL_HA, 27)
+  RELOC_NUMBER (R_NIOS2_TLS_GD16, 28)
+  RELOC_NUMBER (R_NIOS2_TLS_LDM16, 29)
+  RELOC_NUMBER (R_NIOS2_TLS_LDO16, 30)
+  RELOC_NUMBER (R_NIOS2_TLS_IE16, 31)
+  RELOC_NUMBER (R_NIOS2_TLS_LE16, 32)
+  RELOC_NUMBER (R_NIOS2_TLS_DTPMOD, 33)
+  RELOC_NUMBER (R_NIOS2_TLS_DTPREL, 34)
+  RELOC_NUMBER (R_NIOS2_TLS_TPREL, 35)
+  RELOC_NUMBER (R_NIOS2_COPY, 36)
+  RELOC_NUMBER (R_NIOS2_GLOB_DAT, 37)
+  RELOC_NUMBER (R_NIOS2_JUMP_SLOT, 38)
+  RELOC_NUMBER (R_NIOS2_RELATIVE, 39)
+  RELOC_NUMBER (R_NIOS2_GOTOFF, 40)
+  RELOC_NUMBER (R_NIOS2_ILLEGAL, 41)
+END_RELOC_NUMBERS (R_NIOS2_maxext)
+
+/* Processor-specific section flags.  */
+
+/* This is used to mark gp-relative sections.  */
+#define SHF_NIOS2_GPREL	0x10000000
+
+/* Processor-specific dynamic array tags.  */
+
+/* Address of _gp.  */
+#define DT_NIOS2_GP 0x70000002
+
+#endif /* _ELF_NIOS2_H */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]