xref: /openbsd-src/gnu/usr.bin/binutils/bfd/elf64-mips.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
1c88b1d6cSniklas /* MIPS-specific support for 64-bit ELF
2c074d1c9Sdrahn    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3b55d4692Sfgsch    Free Software Foundation, Inc.
4c88b1d6cSniklas    Ian Lance Taylor, Cygnus Support
5b305b0f1Sespie    Linker support added by Mark Mitchell, CodeSourcery, LLC.
6b305b0f1Sespie    <mark@codesourcery.com>
7c88b1d6cSniklas 
8c88b1d6cSniklas This file is part of BFD, the Binary File Descriptor library.
9c88b1d6cSniklas 
10c88b1d6cSniklas This program is free software; you can redistribute it and/or modify
11c88b1d6cSniklas it under the terms of the GNU General Public License as published by
12c88b1d6cSniklas the Free Software Foundation; either version 2 of the License, or
13c88b1d6cSniklas (at your option) any later version.
14c88b1d6cSniklas 
15c88b1d6cSniklas This program is distributed in the hope that it will be useful,
16c88b1d6cSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
17c88b1d6cSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18c88b1d6cSniklas GNU General Public License for more details.
19c88b1d6cSniklas 
20c88b1d6cSniklas You should have received a copy of the GNU General Public License
21c88b1d6cSniklas along with this program; if not, write to the Free Software
22c88b1d6cSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23c88b1d6cSniklas 
24c88b1d6cSniklas /* This file supports the 64-bit MIPS ELF ABI.
25c88b1d6cSniklas 
26c88b1d6cSniklas    The MIPS 64-bit ELF ABI uses an unusual reloc format.  This file
27c88b1d6cSniklas    overrides the usual ELF reloc handling, and handles reading and
28c074d1c9Sdrahn    writing the relocations here.  */
294361b62eSniklas 
30c074d1c9Sdrahn /* TODO: Many things are unsupported, even if there is some code for it
31c074d1c9Sdrahn  .       (which was mostly stolen from elf32-mips.c and slightly adapted).
32c074d1c9Sdrahn  .
33c074d1c9Sdrahn  .   - Relocation handling for REL relocs is wrong in many cases and
34c074d1c9Sdrahn  .     generally untested.
35c074d1c9Sdrahn  .   - Relocation handling for RELA relocs related to GOT support are
36c074d1c9Sdrahn  .     also likely to be wrong.
37c074d1c9Sdrahn  .   - Support for MIPS16 is untested.
38c074d1c9Sdrahn  .   - Combined relocs with RSS_* entries are unsupported.
39c074d1c9Sdrahn  .   - The whole GOT handling for NewABI is missing, some parts of
40c074d1c9Sdrahn  .     the OldABI version is still lying around and should be removed.
41c074d1c9Sdrahn  */
42c88b1d6cSniklas 
43c88b1d6cSniklas #include "bfd.h"
44c88b1d6cSniklas #include "sysdep.h"
45c88b1d6cSniklas #include "libbfd.h"
464361b62eSniklas #include "aout/ar.h"
47c88b1d6cSniklas #include "bfdlink.h"
48c88b1d6cSniklas #include "genlink.h"
49c88b1d6cSniklas #include "elf-bfd.h"
50c074d1c9Sdrahn #include "elfxx-mips.h"
51c88b1d6cSniklas #include "elf/mips.h"
52c88b1d6cSniklas 
53c88b1d6cSniklas /* Get the ECOFF swapping routines.  The 64-bit ABI is not supposed to
54c88b1d6cSniklas    use ECOFF.  However, we support it anyhow for an easier changeover.  */
55c88b1d6cSniklas #include "coff/sym.h"
56c88b1d6cSniklas #include "coff/symconst.h"
57c88b1d6cSniklas #include "coff/internal.h"
58c88b1d6cSniklas #include "coff/ecoff.h"
59c88b1d6cSniklas /* The 64 bit versions of the mdebug data structures are in alpha.h.  */
60c88b1d6cSniklas #include "coff/alpha.h"
61b55d4692Sfgsch #define ECOFF_SIGNED_64
62c88b1d6cSniklas #include "ecoffswap.h"
63c88b1d6cSniklas 
64c88b1d6cSniklas static void mips_elf64_swap_reloc_in
65*007c2a45Smiod   (bfd *, const Elf64_Mips_External_Rel *, Elf64_Mips_Internal_Rela *);
66c88b1d6cSniklas static void mips_elf64_swap_reloca_in
67*007c2a45Smiod   (bfd *, const Elf64_Mips_External_Rela *, Elf64_Mips_Internal_Rela *);
68c88b1d6cSniklas static void mips_elf64_swap_reloc_out
69*007c2a45Smiod   (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rel *);
70c88b1d6cSniklas static void mips_elf64_swap_reloca_out
71*007c2a45Smiod   (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rela *);
72b305b0f1Sespie static void mips_elf64_be_swap_reloc_in
73*007c2a45Smiod   (bfd *, const bfd_byte *, Elf_Internal_Rela *);
74b305b0f1Sespie static void mips_elf64_be_swap_reloc_out
75*007c2a45Smiod   (bfd *, const Elf_Internal_Rela *, bfd_byte *);
76b305b0f1Sespie static void mips_elf64_be_swap_reloca_in
77*007c2a45Smiod   (bfd *, const bfd_byte *, Elf_Internal_Rela *);
78b305b0f1Sespie static void mips_elf64_be_swap_reloca_out
79*007c2a45Smiod   (bfd *, const Elf_Internal_Rela *, bfd_byte *);
80c074d1c9Sdrahn static reloc_howto_type *bfd_elf64_bfd_reloc_type_lookup
81*007c2a45Smiod   (bfd *, bfd_reloc_code_real_type);
82c074d1c9Sdrahn static reloc_howto_type *mips_elf64_rtype_to_howto
83*007c2a45Smiod   (unsigned int, bfd_boolean);
84c074d1c9Sdrahn static void mips_elf64_info_to_howto_rel
85*007c2a45Smiod   (bfd *, arelent *, Elf_Internal_Rela *);
86c074d1c9Sdrahn static void mips_elf64_info_to_howto_rela
87*007c2a45Smiod   (bfd *, arelent *, Elf_Internal_Rela *);
88c074d1c9Sdrahn static long mips_elf64_get_reloc_upper_bound
89*007c2a45Smiod   (bfd *, asection *);
90c074d1c9Sdrahn static long mips_elf64_canonicalize_reloc
91*007c2a45Smiod   (bfd *, asection *, arelent **, asymbol **);
92*007c2a45Smiod static long mips_elf64_get_dynamic_reloc_upper_bound
93*007c2a45Smiod   (bfd *);
94c074d1c9Sdrahn static long mips_elf64_canonicalize_dynamic_reloc
95*007c2a45Smiod   (bfd *, arelent **, asymbol **);
96c074d1c9Sdrahn static bfd_boolean mips_elf64_slurp_one_reloc_table
97*007c2a45Smiod   (bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type, arelent *,
98*007c2a45Smiod    asymbol **, bfd_boolean);
99c074d1c9Sdrahn static bfd_boolean mips_elf64_slurp_reloc_table
100*007c2a45Smiod   (bfd *, asection *, asymbol **, bfd_boolean);
101c074d1c9Sdrahn static void mips_elf64_write_relocs
102*007c2a45Smiod   (bfd *, asection *, void *);
103c074d1c9Sdrahn static void mips_elf64_write_rel
104*007c2a45Smiod   (bfd *, asection *, Elf_Internal_Shdr *, int *, void *);
105c074d1c9Sdrahn static void mips_elf64_write_rela
106*007c2a45Smiod   (bfd *, asection *, Elf_Internal_Shdr *, int *, void *);
107c074d1c9Sdrahn static bfd_reloc_status_type mips_elf64_gprel16_reloc
108*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
109c074d1c9Sdrahn static bfd_reloc_status_type mips_elf64_literal_reloc
110*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
111c074d1c9Sdrahn static bfd_reloc_status_type mips_elf64_gprel32_reloc
112*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
113c074d1c9Sdrahn static bfd_reloc_status_type mips_elf64_shift6_reloc
114*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
115c074d1c9Sdrahn static bfd_reloc_status_type mips16_jump_reloc
116*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
117c074d1c9Sdrahn static bfd_reloc_status_type mips16_gprel_reloc
118*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
119c074d1c9Sdrahn static bfd_boolean mips_elf64_assign_gp
120*007c2a45Smiod   (bfd *, bfd_vma *);
121c074d1c9Sdrahn static bfd_reloc_status_type mips_elf64_final_gp
122*007c2a45Smiod   (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
123c074d1c9Sdrahn static bfd_boolean mips_elf64_object_p
124*007c2a45Smiod   (bfd *);
125c074d1c9Sdrahn static irix_compat_t elf64_mips_irix_compat
126*007c2a45Smiod   (bfd *);
127c074d1c9Sdrahn static bfd_boolean elf64_mips_grok_prstatus
128*007c2a45Smiod   (bfd *, Elf_Internal_Note *);
129c074d1c9Sdrahn static bfd_boolean elf64_mips_grok_psinfo
130*007c2a45Smiod   (bfd *, Elf_Internal_Note *);
131c074d1c9Sdrahn 
132c074d1c9Sdrahn extern const bfd_target bfd_elf64_bigmips_vec;
133c074d1c9Sdrahn extern const bfd_target bfd_elf64_littlemips_vec;
134c88b1d6cSniklas 
135c88b1d6cSniklas /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
136c88b1d6cSniklas    from smaller values.  Start with zero, widen, *then* decrement.  */
137c88b1d6cSniklas #define MINUS_ONE	(((bfd_vma)0) - 1)
138c88b1d6cSniklas 
139b305b0f1Sespie /* The number of local .got entries we reserve.  */
140b305b0f1Sespie #define MIPS_RESERVED_GOTNO (2)
141c074d1c9Sdrahn 
142c88b1d6cSniklas /* The relocation table used for SHT_REL sections.  */
143c88b1d6cSniklas 
144c88b1d6cSniklas static reloc_howto_type mips_elf64_howto_table_rel[] =
145c88b1d6cSniklas {
146c88b1d6cSniklas   /* No relocation.  */
147c88b1d6cSniklas   HOWTO (R_MIPS_NONE,		/* type */
148c88b1d6cSniklas 	 0,			/* rightshift */
149c88b1d6cSniklas 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
150c88b1d6cSniklas 	 0,			/* bitsize */
151c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
152c88b1d6cSniklas 	 0,			/* bitpos */
153c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
154*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
155c88b1d6cSniklas 	 "R_MIPS_NONE",		/* name */
156c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
157c88b1d6cSniklas 	 0,			/* src_mask */
158c88b1d6cSniklas 	 0,			/* dst_mask */
159c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
160c88b1d6cSniklas 
161c88b1d6cSniklas   /* 16 bit relocation.  */
162c88b1d6cSniklas   HOWTO (R_MIPS_16,		/* type */
163c88b1d6cSniklas 	 0,			/* rightshift */
164c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
165c88b1d6cSniklas 	 16,			/* bitsize */
166c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
167c88b1d6cSniklas 	 0,			/* bitpos */
168c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
169*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
170c88b1d6cSniklas 	 "R_MIPS_16",		/* name */
171c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
172c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
173c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
174c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
175c88b1d6cSniklas 
176c88b1d6cSniklas   /* 32 bit relocation.  */
177c88b1d6cSniklas   HOWTO (R_MIPS_32,		/* type */
178c88b1d6cSniklas 	 0,			/* rightshift */
179c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
180c88b1d6cSniklas 	 32,			/* bitsize */
181c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
182c88b1d6cSniklas 	 0,			/* bitpos */
183c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
184*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
185c88b1d6cSniklas 	 "R_MIPS_32",		/* name */
186c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
187c88b1d6cSniklas 	 0xffffffff,		/* src_mask */
188c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
189c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
190c88b1d6cSniklas 
191c88b1d6cSniklas   /* 32 bit symbol relative relocation.  */
192c88b1d6cSniklas   HOWTO (R_MIPS_REL32,		/* type */
193c88b1d6cSniklas 	 0,			/* rightshift */
194c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
195c88b1d6cSniklas 	 32,			/* bitsize */
196c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
197c88b1d6cSniklas 	 0,			/* bitpos */
198c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
199*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
200c88b1d6cSniklas 	 "R_MIPS_REL32",	/* name */
201c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
202c88b1d6cSniklas 	 0xffffffff,		/* src_mask */
203c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
204c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
205c88b1d6cSniklas 
206c074d1c9Sdrahn   /* 26 bit jump address.  */
207c88b1d6cSniklas   HOWTO (R_MIPS_26,		/* type */
208c88b1d6cSniklas 	 2,			/* rightshift */
209c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
210c88b1d6cSniklas 	 26,			/* bitsize */
211c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
212c88b1d6cSniklas 	 0,			/* bitpos */
213c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
214c88b1d6cSniklas 				/* This needs complex overflow
215c074d1c9Sdrahn 				   detection, because the upper 36
216b55d4692Sfgsch 				   bits must match the PC + 4.  */
217*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
218c88b1d6cSniklas 	 "R_MIPS_26",		/* name */
219c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
220c074d1c9Sdrahn 	 0x03ffffff,		/* src_mask */
221c074d1c9Sdrahn 	 0x03ffffff,		/* dst_mask */
222c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
223c074d1c9Sdrahn 
224c074d1c9Sdrahn   /* R_MIPS_HI16 and R_MIPS_LO16 are unsupported for NewABI REL.
225c074d1c9Sdrahn      However, the native IRIX6 tools use them, so we try our best. */
226c88b1d6cSniklas 
227c88b1d6cSniklas   /* High 16 bits of symbol value.  */
228c88b1d6cSniklas   HOWTO (R_MIPS_HI16,		/* type */
229*007c2a45Smiod 	 16,			/* rightshift */
230c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
231c88b1d6cSniklas 	 16,			/* bitsize */
232c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
233c88b1d6cSniklas 	 0,			/* bitpos */
234c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
235*007c2a45Smiod 	 _bfd_mips_elf_hi16_reloc, /* special_function */
236c88b1d6cSniklas 	 "R_MIPS_HI16",		/* name */
237c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
238c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
239c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
240c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
241c88b1d6cSniklas 
242c88b1d6cSniklas   /* Low 16 bits of symbol value.  */
243c88b1d6cSniklas   HOWTO (R_MIPS_LO16,		/* type */
244c88b1d6cSniklas 	 0,			/* rightshift */
245c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
246c88b1d6cSniklas 	 16,			/* bitsize */
247c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
248c88b1d6cSniklas 	 0,			/* bitpos */
249c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
250*007c2a45Smiod 	 _bfd_mips_elf_lo16_reloc, /* special_function */
251c88b1d6cSniklas 	 "R_MIPS_LO16",		/* name */
252c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
253c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
254c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
255c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
256c88b1d6cSniklas 
257c88b1d6cSniklas   /* GP relative reference.  */
258c88b1d6cSniklas   HOWTO (R_MIPS_GPREL16,	/* type */
259c88b1d6cSniklas 	 0,			/* rightshift */
260c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
261c88b1d6cSniklas 	 16,			/* bitsize */
262c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
263c88b1d6cSniklas 	 0,			/* bitpos */
264c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
265c074d1c9Sdrahn 	 mips_elf64_gprel16_reloc, /* special_function */
266c88b1d6cSniklas 	 "R_MIPS_GPREL16",	/* name */
267c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
268c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
269c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
270c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
271c88b1d6cSniklas 
272c88b1d6cSniklas   /* Reference to literal section.  */
273c88b1d6cSniklas   HOWTO (R_MIPS_LITERAL,	/* type */
274c88b1d6cSniklas 	 0,			/* rightshift */
275c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
276c88b1d6cSniklas 	 16,			/* bitsize */
277c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
278c88b1d6cSniklas 	 0,			/* bitpos */
279c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
280c074d1c9Sdrahn 	 mips_elf64_literal_reloc, /* special_function */
281c88b1d6cSniklas 	 "R_MIPS_LITERAL",	/* name */
282c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
283c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
284c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
285c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
286c88b1d6cSniklas 
287c88b1d6cSniklas   /* Reference to global offset table.  */
288c88b1d6cSniklas   HOWTO (R_MIPS_GOT16,		/* type */
289c88b1d6cSniklas 	 0,			/* rightshift */
290c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
291c88b1d6cSniklas 	 16,			/* bitsize */
292c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
293c88b1d6cSniklas 	 0,			/* bitpos */
294c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
295*007c2a45Smiod 	 _bfd_mips_elf_got16_reloc, /* special_function */
296c88b1d6cSniklas 	 "R_MIPS_GOT16",	/* name */
297c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
298c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
299c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
300c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
301c88b1d6cSniklas 
302c88b1d6cSniklas   /* 16 bit PC relative reference.  */
303c88b1d6cSniklas   HOWTO (R_MIPS_PC16,		/* type */
304c88b1d6cSniklas 	 0,			/* rightshift */
305c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
306c88b1d6cSniklas 	 16,			/* bitsize */
307c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
308c88b1d6cSniklas 	 0,			/* bitpos */
309c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
310*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
311c88b1d6cSniklas 	 "R_MIPS_PC16",		/* name */
312c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
313c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
314c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
315c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
316c88b1d6cSniklas 
317c88b1d6cSniklas   /* 16 bit call through global offset table.  */
318c88b1d6cSniklas   HOWTO (R_MIPS_CALL16,		/* type */
319c88b1d6cSniklas 	 0,			/* rightshift */
320c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
321c88b1d6cSniklas 	 16,			/* bitsize */
322c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
323c88b1d6cSniklas 	 0,			/* bitpos */
324c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
325*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
326c88b1d6cSniklas 	 "R_MIPS_CALL16",	/* name */
327c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
328c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
329c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
330c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
331c88b1d6cSniklas 
332c88b1d6cSniklas   /* 32 bit GP relative reference.  */
333c88b1d6cSniklas   HOWTO (R_MIPS_GPREL32,	/* type */
334c88b1d6cSniklas 	 0,			/* rightshift */
335c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
336c88b1d6cSniklas 	 32,			/* bitsize */
337c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
338c88b1d6cSniklas 	 0,			/* bitpos */
339c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
340c074d1c9Sdrahn 	 mips_elf64_gprel32_reloc, /* special_function */
341c88b1d6cSniklas 	 "R_MIPS_GPREL32",	/* name */
342c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
343c88b1d6cSniklas 	 0xffffffff,		/* src_mask */
344c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
345c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
346c88b1d6cSniklas 
347c074d1c9Sdrahn   EMPTY_HOWTO (13),
348c074d1c9Sdrahn   EMPTY_HOWTO (14),
349c074d1c9Sdrahn   EMPTY_HOWTO (15),
350c88b1d6cSniklas 
351c88b1d6cSniklas   /* A 5 bit shift field.  */
352c88b1d6cSniklas   HOWTO (R_MIPS_SHIFT5,		/* type */
353c88b1d6cSniklas 	 0,			/* rightshift */
354c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
355c88b1d6cSniklas 	 5,			/* bitsize */
356c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
357c88b1d6cSniklas 	 6,			/* bitpos */
358c88b1d6cSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
359*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
360c88b1d6cSniklas 	 "R_MIPS_SHIFT5",	/* name */
361c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
362c88b1d6cSniklas 	 0x000007c0,		/* src_mask */
363c88b1d6cSniklas 	 0x000007c0,		/* dst_mask */
364c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
365c88b1d6cSniklas 
366c88b1d6cSniklas   /* A 6 bit shift field.  */
367c88b1d6cSniklas   HOWTO (R_MIPS_SHIFT6,		/* type */
368c88b1d6cSniklas 	 0,			/* rightshift */
369c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
370c88b1d6cSniklas 	 6,			/* bitsize */
371c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
372c88b1d6cSniklas 	 6,			/* bitpos */
373c88b1d6cSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
374c074d1c9Sdrahn 	 mips_elf64_shift6_reloc, /* special_function */
375c88b1d6cSniklas 	 "R_MIPS_SHIFT6",	/* name */
376c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
377c88b1d6cSniklas 	 0x000007c4,		/* src_mask */
378c88b1d6cSniklas 	 0x000007c4,		/* dst_mask */
379c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
380c88b1d6cSniklas 
381c88b1d6cSniklas   /* 64 bit relocation.  */
382c88b1d6cSniklas   HOWTO (R_MIPS_64,		/* type */
383c88b1d6cSniklas 	 0,			/* rightshift */
384c88b1d6cSniklas 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
385c88b1d6cSniklas 	 64,			/* bitsize */
386c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
387c88b1d6cSniklas 	 0,			/* bitpos */
388c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
389*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
390c88b1d6cSniklas 	 "R_MIPS_64",		/* name */
391c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
392c88b1d6cSniklas 	 MINUS_ONE,		/* src_mask */
393c88b1d6cSniklas 	 MINUS_ONE,		/* dst_mask */
394c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
395c88b1d6cSniklas 
396c88b1d6cSniklas   /* Displacement in the global offset table.  */
397c88b1d6cSniklas   HOWTO (R_MIPS_GOT_DISP,	/* type */
398c88b1d6cSniklas 	 0,			/* rightshift */
399c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
400c88b1d6cSniklas 	 16,			/* bitsize */
401c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
402c88b1d6cSniklas 	 0,			/* bitpos */
403c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
404*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
405c88b1d6cSniklas 	 "R_MIPS_GOT_DISP",	/* name */
406c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
407c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
408c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
409c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
410c88b1d6cSniklas 
411c88b1d6cSniklas   /* Displacement to page pointer in the global offset table.  */
412c88b1d6cSniklas   HOWTO (R_MIPS_GOT_PAGE,	/* type */
413c88b1d6cSniklas 	 0,			/* rightshift */
414c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
415c88b1d6cSniklas 	 16,			/* bitsize */
416c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
417c88b1d6cSniklas 	 0,			/* bitpos */
418c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
419*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
420c88b1d6cSniklas 	 "R_MIPS_GOT_PAGE",	/* name */
421c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
422c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
423c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
424c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
425c88b1d6cSniklas 
426c88b1d6cSniklas   /* Offset from page pointer in the global offset table.  */
427c88b1d6cSniklas   HOWTO (R_MIPS_GOT_OFST,	/* type */
428c88b1d6cSniklas 	 0,			/* rightshift */
429c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
430c88b1d6cSniklas 	 16,			/* bitsize */
431c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
432c88b1d6cSniklas 	 0,			/* bitpos */
433c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
434*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
435c88b1d6cSniklas 	 "R_MIPS_GOT_OFST",	/* name */
436c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
437c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
438c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
439c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
440c88b1d6cSniklas 
441c88b1d6cSniklas   /* High 16 bits of displacement in global offset table.  */
442c88b1d6cSniklas   HOWTO (R_MIPS_GOT_HI16,	/* type */
443c88b1d6cSniklas 	 0,			/* rightshift */
444c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
445c88b1d6cSniklas 	 16,			/* bitsize */
446c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
447c88b1d6cSniklas 	 0,			/* bitpos */
448c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
449*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
450c88b1d6cSniklas 	 "R_MIPS_GOT_HI16",	/* name */
451c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
452c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
453c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
454c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
455c88b1d6cSniklas 
456c88b1d6cSniklas   /* Low 16 bits of displacement in global offset table.  */
457c88b1d6cSniklas   HOWTO (R_MIPS_GOT_LO16,	/* type */
458c88b1d6cSniklas 	 0,			/* rightshift */
459c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
460c88b1d6cSniklas 	 16,			/* bitsize */
461c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
462c88b1d6cSniklas 	 0,			/* bitpos */
463c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
464*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
465c88b1d6cSniklas 	 "R_MIPS_GOT_LO16",	/* name */
466c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
467c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
468c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
469c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
470c88b1d6cSniklas 
471*007c2a45Smiod   /* 64 bit subtraction.  */
472c88b1d6cSniklas   HOWTO (R_MIPS_SUB,		/* type */
473c88b1d6cSniklas 	 0,			/* rightshift */
474c88b1d6cSniklas 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
475c88b1d6cSniklas 	 64,			/* bitsize */
476c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
477c88b1d6cSniklas 	 0,			/* bitpos */
478c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
479*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
480c88b1d6cSniklas 	 "R_MIPS_SUB",		/* name */
481c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
482c88b1d6cSniklas 	 MINUS_ONE,		/* src_mask */
483c88b1d6cSniklas 	 MINUS_ONE,		/* dst_mask */
484c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
485c88b1d6cSniklas 
486c88b1d6cSniklas   /* Insert the addend as an instruction.  */
487c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
488c88b1d6cSniklas   HOWTO (R_MIPS_INSERT_A,	/* type */
489c88b1d6cSniklas 	 0,			/* rightshift */
490c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
491c074d1c9Sdrahn 	 32,			/* bitsize */
492c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
493c88b1d6cSniklas 	 0,			/* bitpos */
494c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
495*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
496c88b1d6cSniklas 	 "R_MIPS_INSERT_A",	/* name */
497c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
498c074d1c9Sdrahn 	 0xffffffff,		/* src_mask */
499c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
500c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
501c88b1d6cSniklas 
502c88b1d6cSniklas   /* Insert the addend as an instruction, and change all relocations
503c88b1d6cSniklas      to refer to the old instruction at the address.  */
504c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
505c88b1d6cSniklas   HOWTO (R_MIPS_INSERT_B,	/* type */
506c88b1d6cSniklas 	 0,			/* rightshift */
507c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
508c074d1c9Sdrahn 	 32,			/* bitsize */
509c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
510c88b1d6cSniklas 	 0,			/* bitpos */
511c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
512*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
513c88b1d6cSniklas 	 "R_MIPS_INSERT_B",	/* name */
514c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
515c074d1c9Sdrahn 	 0xffffffff,		/* src_mask */
516c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
517c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
518c88b1d6cSniklas 
519c88b1d6cSniklas   /* Delete a 32 bit instruction.  */
520c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
521c88b1d6cSniklas   HOWTO (R_MIPS_DELETE,		/* type */
522c88b1d6cSniklas 	 0,			/* rightshift */
523c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
524c074d1c9Sdrahn 	 32,			/* bitsize */
525c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
526c88b1d6cSniklas 	 0,			/* bitpos */
527c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
528*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
529c88b1d6cSniklas 	 "R_MIPS_DELETE",	/* name */
530c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
531c074d1c9Sdrahn 	 0xffffffff,		/* src_mask */
532c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
533c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
534c88b1d6cSniklas 
535c074d1c9Sdrahn   /* The MIPS ELF64 ABI Draft wants us to support these for REL relocations.
536c074d1c9Sdrahn      We don't, because
537c074d1c9Sdrahn        a) It means building the addend from a R_MIPS_HIGHEST/R_MIPS_HIGHER/
538c074d1c9Sdrahn 	  R_MIPS_HI16/R_MIPS_LO16 sequence with varying ordering, using
539c074d1c9Sdrahn 	  fallable heuristics.
540c074d1c9Sdrahn        b) No other NewABI toolchain actually emits such relocations.  */
541c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_HIGHER),
542c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_HIGHEST),
543c88b1d6cSniklas 
544c88b1d6cSniklas   /* High 16 bits of displacement in global offset table.  */
545c88b1d6cSniklas   HOWTO (R_MIPS_CALL_HI16,	/* type */
546c88b1d6cSniklas 	 0,			/* rightshift */
547c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
548c88b1d6cSniklas 	 16,			/* bitsize */
549c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
550c88b1d6cSniklas 	 0,			/* bitpos */
551c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
552*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
553c88b1d6cSniklas 	 "R_MIPS_CALL_HI16",	/* name */
554c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
555c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
556c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
557c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
558c88b1d6cSniklas 
559c88b1d6cSniklas   /* Low 16 bits of displacement in global offset table.  */
560c88b1d6cSniklas   HOWTO (R_MIPS_CALL_LO16,	/* type */
561c88b1d6cSniklas 	 0,			/* rightshift */
562c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
563c88b1d6cSniklas 	 16,			/* bitsize */
564c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
565c88b1d6cSniklas 	 0,			/* bitpos */
566c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
567*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
568c88b1d6cSniklas 	 "R_MIPS_CALL_LO16",	/* name */
569c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
570c88b1d6cSniklas 	 0x0000ffff,		/* src_mask */
571c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
572c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
573c88b1d6cSniklas 
574c074d1c9Sdrahn   /* Section displacement, used by an associated event location section.  */
575c88b1d6cSniklas   HOWTO (R_MIPS_SCN_DISP,	/* type */
576c88b1d6cSniklas 	 0,			/* rightshift */
577c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
578c074d1c9Sdrahn 	 32,			/* bitsize */
579c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
580c88b1d6cSniklas 	 0,			/* bitpos */
581c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
582*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
583c88b1d6cSniklas 	 "R_MIPS_SCN_DISP",	/* name */
584c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
585c074d1c9Sdrahn 	 0xffffffff,		/* src_mask */
586c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
587c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
588c88b1d6cSniklas 
589c88b1d6cSniklas   HOWTO (R_MIPS_REL16,		/* type */
590c88b1d6cSniklas 	 0,			/* rightshift */
591c074d1c9Sdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
592c074d1c9Sdrahn 	 16,			/* bitsize */
593c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
594c88b1d6cSniklas 	 0,			/* bitpos */
595c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
596*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
597c88b1d6cSniklas 	 "R_MIPS_REL16",	/* name */
598c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
599c074d1c9Sdrahn 	 0xffff,		/* src_mask */
600c074d1c9Sdrahn 	 0xffff,		/* dst_mask */
601c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
602c88b1d6cSniklas 
603c074d1c9Sdrahn   /* These two are obsolete.  */
604c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
605c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_PJUMP),
606c88b1d6cSniklas 
607c074d1c9Sdrahn   /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section.
608c074d1c9Sdrahn      It must be used for multigot GOT's (and only there).  */
609c88b1d6cSniklas   HOWTO (R_MIPS_RELGOT,		/* type */
610c88b1d6cSniklas 	 0,			/* rightshift */
611c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
612c074d1c9Sdrahn 	 32,			/* bitsize */
613c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
614c88b1d6cSniklas 	 0,			/* bitpos */
615c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
616*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
617c88b1d6cSniklas 	 "R_MIPS_RELGOT",	/* name */
618c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
619c074d1c9Sdrahn 	 0xffffffff,		/* src_mask */
620c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
621c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
622b305b0f1Sespie 
623b305b0f1Sespie   /* Protected jump conversion.  This is an optimization hint.  No
624b305b0f1Sespie      relocation is required for correctness.  */
625b305b0f1Sespie   HOWTO (R_MIPS_JALR,	        /* type */
626b305b0f1Sespie 	 0,			/* rightshift */
627c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
628c074d1c9Sdrahn 	 32,			/* bitsize */
629c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
630b305b0f1Sespie 	 0,			/* bitpos */
631b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
632*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
633b305b0f1Sespie 	 "R_MIPS_JALR",	        /* name */
634c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
635c074d1c9Sdrahn 	 0,			/* src_mask */
636b305b0f1Sespie 	 0x00000000,		/* dst_mask */
637c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
638c88b1d6cSniklas };
639c88b1d6cSniklas 
640c88b1d6cSniklas /* The relocation table used for SHT_RELA sections.  */
641c88b1d6cSniklas 
642c88b1d6cSniklas static reloc_howto_type mips_elf64_howto_table_rela[] =
643c88b1d6cSniklas {
644c88b1d6cSniklas   /* No relocation.  */
645c88b1d6cSniklas   HOWTO (R_MIPS_NONE,		/* type */
646c88b1d6cSniklas 	 0,			/* rightshift */
647c88b1d6cSniklas 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
648c88b1d6cSniklas 	 0,			/* bitsize */
649c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
650c88b1d6cSniklas 	 0,			/* bitpos */
651c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
652*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
653c88b1d6cSniklas 	 "R_MIPS_NONE",		/* name */
654c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
655c88b1d6cSniklas 	 0,			/* src_mask */
656c88b1d6cSniklas 	 0,			/* dst_mask */
657c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
658c88b1d6cSniklas 
659c88b1d6cSniklas   /* 16 bit relocation.  */
660c88b1d6cSniklas   HOWTO (R_MIPS_16,		/* type */
661c88b1d6cSniklas 	 0,			/* rightshift */
662c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
663c88b1d6cSniklas 	 16,			/* bitsize */
664c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
665c88b1d6cSniklas 	 0,			/* bitpos */
666c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
667*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
668c88b1d6cSniklas 	 "R_MIPS_16",		/* name */
669c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
670c88b1d6cSniklas 	 0,			/* src_mask */
671c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
672c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
673c88b1d6cSniklas 
674c88b1d6cSniklas   /* 32 bit relocation.  */
675c88b1d6cSniklas   HOWTO (R_MIPS_32,		/* type */
676c88b1d6cSniklas 	 0,			/* rightshift */
677c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
678c88b1d6cSniklas 	 32,			/* bitsize */
679c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
680c88b1d6cSniklas 	 0,			/* bitpos */
681c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
682*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
683c88b1d6cSniklas 	 "R_MIPS_32",		/* name */
684c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
685c88b1d6cSniklas 	 0,			/* src_mask */
686c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
687c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
688c88b1d6cSniklas 
689c88b1d6cSniklas   /* 32 bit symbol relative relocation.  */
690c88b1d6cSniklas   HOWTO (R_MIPS_REL32,		/* type */
691c88b1d6cSniklas 	 0,			/* rightshift */
692c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
693c88b1d6cSniklas 	 32,			/* bitsize */
694c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
695c88b1d6cSniklas 	 0,			/* bitpos */
696c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
697*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
698c88b1d6cSniklas 	 "R_MIPS_REL32",	/* name */
699c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
700c88b1d6cSniklas 	 0,			/* src_mask */
701c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
702c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
703c88b1d6cSniklas 
704c074d1c9Sdrahn   /* 26 bit jump address.  */
705c88b1d6cSniklas   HOWTO (R_MIPS_26,		/* type */
706c88b1d6cSniklas 	 2,			/* rightshift */
707c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
708c88b1d6cSniklas 	 26,			/* bitsize */
709c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
710c88b1d6cSniklas 	 0,			/* bitpos */
711c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
712c88b1d6cSniklas 				/* This needs complex overflow
713c074d1c9Sdrahn 				   detection, because the upper 36
714b55d4692Sfgsch 				   bits must match the PC + 4.  */
715*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
716c88b1d6cSniklas 	 "R_MIPS_26",		/* name */
717c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
718c88b1d6cSniklas 	 0,			/* src_mask */
719c074d1c9Sdrahn 	 0x03ffffff,		/* dst_mask */
720c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
721c88b1d6cSniklas 
722c88b1d6cSniklas   /* High 16 bits of symbol value.  */
723c88b1d6cSniklas   HOWTO (R_MIPS_HI16,		/* type */
724c88b1d6cSniklas 	 0,			/* rightshift */
725c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
726c88b1d6cSniklas 	 16,			/* bitsize */
727c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
728c88b1d6cSniklas 	 0,			/* bitpos */
729c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
730*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
731c88b1d6cSniklas 	 "R_MIPS_HI16",		/* name */
732c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
733c88b1d6cSniklas 	 0,			/* src_mask */
734c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
735c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
736c88b1d6cSniklas 
737c88b1d6cSniklas   /* Low 16 bits of symbol value.  */
738c88b1d6cSniklas   HOWTO (R_MIPS_LO16,		/* type */
739c88b1d6cSniklas 	 0,			/* rightshift */
740c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
741c88b1d6cSniklas 	 16,			/* bitsize */
742c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
743c88b1d6cSniklas 	 0,			/* bitpos */
744c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
745*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
746c88b1d6cSniklas 	 "R_MIPS_LO16",		/* name */
747c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
748c88b1d6cSniklas 	 0,			/* src_mask */
749c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
750c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
751c88b1d6cSniklas 
752c88b1d6cSniklas   /* GP relative reference.  */
753c88b1d6cSniklas   HOWTO (R_MIPS_GPREL16,	/* type */
754c88b1d6cSniklas 	 0,			/* rightshift */
755c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
756c88b1d6cSniklas 	 16,			/* bitsize */
757c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
758c88b1d6cSniklas 	 0,			/* bitpos */
759c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
760c074d1c9Sdrahn 	 mips_elf64_gprel16_reloc, /* special_function */
761c88b1d6cSniklas 	 "R_MIPS_GPREL16",	/* name */
762c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
763c88b1d6cSniklas 	 0,			/* src_mask */
764c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
765c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
766c88b1d6cSniklas 
767c88b1d6cSniklas   /* Reference to literal section.  */
768c88b1d6cSniklas   HOWTO (R_MIPS_LITERAL,	/* type */
769c88b1d6cSniklas 	 0,			/* rightshift */
770c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
771c88b1d6cSniklas 	 16,			/* bitsize */
772c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
773c88b1d6cSniklas 	 0,			/* bitpos */
774c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
775c074d1c9Sdrahn 	 mips_elf64_literal_reloc, /* special_function */
776c88b1d6cSniklas 	 "R_MIPS_LITERAL",	/* name */
777c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
778c88b1d6cSniklas 	 0,			/* src_mask */
779c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
780c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
781c88b1d6cSniklas 
782c88b1d6cSniklas   /* Reference to global offset table.  */
783c88b1d6cSniklas   HOWTO (R_MIPS_GOT16,		/* type */
784c88b1d6cSniklas 	 0,			/* rightshift */
785c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
786c88b1d6cSniklas 	 16,			/* bitsize */
787c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
788c88b1d6cSniklas 	 0,			/* bitpos */
789c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
790*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
791c88b1d6cSniklas 	 "R_MIPS_GOT16",	/* name */
792c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
793c88b1d6cSniklas 	 0,			/* src_mask */
794c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
795c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
796c88b1d6cSniklas 
797c88b1d6cSniklas   /* 16 bit PC relative reference.  */
798c88b1d6cSniklas   HOWTO (R_MIPS_PC16,		/* type */
799c88b1d6cSniklas 	 0,			/* rightshift */
800c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
801c88b1d6cSniklas 	 16,			/* bitsize */
802c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
803c88b1d6cSniklas 	 0,			/* bitpos */
804c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
805*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
806c88b1d6cSniklas 	 "R_MIPS_PC16",		/* name */
807c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
808c88b1d6cSniklas 	 0,			/* src_mask */
809c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
810c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
811c88b1d6cSniklas 
812c88b1d6cSniklas   /* 16 bit call through global offset table.  */
813c88b1d6cSniklas   HOWTO (R_MIPS_CALL16,		/* type */
814c88b1d6cSniklas 	 0,			/* rightshift */
815c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
816c88b1d6cSniklas 	 16,			/* bitsize */
817c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
818c88b1d6cSniklas 	 0,			/* bitpos */
819c88b1d6cSniklas 	 complain_overflow_signed, /* complain_on_overflow */
820*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
821c88b1d6cSniklas 	 "R_MIPS_CALL16",	/* name */
822c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
823c88b1d6cSniklas 	 0,			/* src_mask */
824c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
825c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
826c88b1d6cSniklas 
827c88b1d6cSniklas   /* 32 bit GP relative reference.  */
828c88b1d6cSniklas   HOWTO (R_MIPS_GPREL32,	/* type */
829c88b1d6cSniklas 	 0,			/* rightshift */
830c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
831c88b1d6cSniklas 	 32,			/* bitsize */
832c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
833c88b1d6cSniklas 	 0,			/* bitpos */
834c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
835c074d1c9Sdrahn 	 mips_elf64_gprel32_reloc, /* special_function */
836c88b1d6cSniklas 	 "R_MIPS_GPREL32",	/* name */
837c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
838c88b1d6cSniklas 	 0,			/* src_mask */
839c88b1d6cSniklas 	 0xffffffff,		/* dst_mask */
840c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
841c88b1d6cSniklas 
842c074d1c9Sdrahn   EMPTY_HOWTO (13),
843c074d1c9Sdrahn   EMPTY_HOWTO (14),
844c074d1c9Sdrahn   EMPTY_HOWTO (15),
845c88b1d6cSniklas 
846c88b1d6cSniklas   /* A 5 bit shift field.  */
847c88b1d6cSniklas   HOWTO (R_MIPS_SHIFT5,		/* type */
848c88b1d6cSniklas 	 0,			/* rightshift */
849c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
850c88b1d6cSniklas 	 5,			/* bitsize */
851c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
852c88b1d6cSniklas 	 6,			/* bitpos */
853c88b1d6cSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
854*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
855c88b1d6cSniklas 	 "R_MIPS_SHIFT5",	/* name */
856c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
857c88b1d6cSniklas 	 0,			/* src_mask */
858c88b1d6cSniklas 	 0x000007c0,		/* dst_mask */
859c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
860c88b1d6cSniklas 
861c88b1d6cSniklas   /* A 6 bit shift field.  */
862c88b1d6cSniklas   HOWTO (R_MIPS_SHIFT6,		/* type */
863c88b1d6cSniklas 	 0,			/* rightshift */
864c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
865c88b1d6cSniklas 	 6,			/* bitsize */
866c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
867c88b1d6cSniklas 	 6,			/* bitpos */
868c88b1d6cSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
869c074d1c9Sdrahn 	 mips_elf64_shift6_reloc, /* special_function */
870c88b1d6cSniklas 	 "R_MIPS_SHIFT6",	/* name */
871c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
872c88b1d6cSniklas 	 0,			/* src_mask */
873c88b1d6cSniklas 	 0x000007c4,		/* dst_mask */
874c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
875c88b1d6cSniklas 
876c88b1d6cSniklas   /* 64 bit relocation.  */
877c88b1d6cSniklas   HOWTO (R_MIPS_64,		/* type */
878c88b1d6cSniklas 	 0,			/* rightshift */
879c88b1d6cSniklas 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
880c88b1d6cSniklas 	 64,			/* bitsize */
881c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
882c88b1d6cSniklas 	 0,			/* bitpos */
883c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
884*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
885c88b1d6cSniklas 	 "R_MIPS_64",		/* name */
886c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
887c88b1d6cSniklas 	 0,			/* src_mask */
888c88b1d6cSniklas 	 MINUS_ONE,		/* dst_mask */
889c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
890c88b1d6cSniklas 
891c88b1d6cSniklas   /* Displacement in the global offset table.  */
892c88b1d6cSniklas   HOWTO (R_MIPS_GOT_DISP,	/* type */
893c88b1d6cSniklas 	 0,			/* rightshift */
894c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
895c88b1d6cSniklas 	 16,			/* bitsize */
896c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
897c88b1d6cSniklas 	 0,			/* bitpos */
898c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
899*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
900c88b1d6cSniklas 	 "R_MIPS_GOT_DISP",	/* name */
901c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
902c88b1d6cSniklas 	 0,			/* src_mask */
903c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
904c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
905c88b1d6cSniklas 
906c88b1d6cSniklas   /* Displacement to page pointer in the global offset table.  */
907c88b1d6cSniklas   HOWTO (R_MIPS_GOT_PAGE,	/* type */
908c88b1d6cSniklas 	 0,			/* rightshift */
909c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
910c88b1d6cSniklas 	 16,			/* bitsize */
911c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
912c88b1d6cSniklas 	 0,			/* bitpos */
913c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
914*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
915c88b1d6cSniklas 	 "R_MIPS_GOT_PAGE",	/* name */
916c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
917c88b1d6cSniklas 	 0,			/* src_mask */
918c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
919c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
920c88b1d6cSniklas 
921c88b1d6cSniklas   /* Offset from page pointer in the global offset table.  */
922c88b1d6cSniklas   HOWTO (R_MIPS_GOT_OFST,	/* type */
923c88b1d6cSniklas 	 0,			/* rightshift */
924c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
925c88b1d6cSniklas 	 16,			/* bitsize */
926c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
927c88b1d6cSniklas 	 0,			/* bitpos */
928c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
929*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
930c88b1d6cSniklas 	 "R_MIPS_GOT_OFST",	/* name */
931c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
932c88b1d6cSniklas 	 0,			/* src_mask */
933c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
934c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
935c88b1d6cSniklas 
936c88b1d6cSniklas   /* High 16 bits of displacement in global offset table.  */
937c88b1d6cSniklas   HOWTO (R_MIPS_GOT_HI16,	/* type */
938c88b1d6cSniklas 	 0,			/* rightshift */
939c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
940c88b1d6cSniklas 	 16,			/* bitsize */
941c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
942c88b1d6cSniklas 	 0,			/* bitpos */
943c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
944*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
945c88b1d6cSniklas 	 "R_MIPS_GOT_HI16",	/* name */
946c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
947c88b1d6cSniklas 	 0,			/* src_mask */
948c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
949c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
950c88b1d6cSniklas 
951c88b1d6cSniklas   /* Low 16 bits of displacement in global offset table.  */
952c88b1d6cSniklas   HOWTO (R_MIPS_GOT_LO16,	/* type */
953c88b1d6cSniklas 	 0,			/* rightshift */
954c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
955c88b1d6cSniklas 	 16,			/* bitsize */
956c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
957c88b1d6cSniklas 	 0,			/* bitpos */
958c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
959*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
960c88b1d6cSniklas 	 "R_MIPS_GOT_LO16",	/* name */
961c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
962c88b1d6cSniklas 	 0,			/* src_mask */
963c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
964c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
965c88b1d6cSniklas 
966*007c2a45Smiod   /* 64 bit subtraction.  */
967c88b1d6cSniklas   HOWTO (R_MIPS_SUB,		/* type */
968c88b1d6cSniklas 	 0,			/* rightshift */
969c88b1d6cSniklas 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
970c88b1d6cSniklas 	 64,			/* bitsize */
971c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
972c88b1d6cSniklas 	 0,			/* bitpos */
973c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
974*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
975c88b1d6cSniklas 	 "R_MIPS_SUB",		/* name */
976c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
977c88b1d6cSniklas 	 0,			/* src_mask */
978c88b1d6cSniklas 	 MINUS_ONE,		/* dst_mask */
979c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
980c88b1d6cSniklas 
981c88b1d6cSniklas   /* Insert the addend as an instruction.  */
982c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
983c88b1d6cSniklas   HOWTO (R_MIPS_INSERT_A,	/* type */
984c88b1d6cSniklas 	 0,			/* rightshift */
985c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
986c074d1c9Sdrahn 	 32,			/* bitsize */
987c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
988c88b1d6cSniklas 	 0,			/* bitpos */
989c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
990*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
991c88b1d6cSniklas 	 "R_MIPS_INSERT_A",	/* name */
992c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
993c88b1d6cSniklas 	 0,			/* src_mask */
994c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
995c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
996c88b1d6cSniklas 
997c88b1d6cSniklas   /* Insert the addend as an instruction, and change all relocations
998c88b1d6cSniklas      to refer to the old instruction at the address.  */
999c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
1000c88b1d6cSniklas   HOWTO (R_MIPS_INSERT_B,	/* type */
1001c88b1d6cSniklas 	 0,			/* rightshift */
1002c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1003c074d1c9Sdrahn 	 32,			/* bitsize */
1004c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1005c88b1d6cSniklas 	 0,			/* bitpos */
1006c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1007*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1008c88b1d6cSniklas 	 "R_MIPS_INSERT_B",	/* name */
1009c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1010c88b1d6cSniklas 	 0,			/* src_mask */
1011c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
1012c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1013c88b1d6cSniklas 
1014c88b1d6cSniklas   /* Delete a 32 bit instruction.  */
1015c88b1d6cSniklas   /* FIXME: Not handled correctly.  */
1016c88b1d6cSniklas   HOWTO (R_MIPS_DELETE,		/* type */
1017c88b1d6cSniklas 	 0,			/* rightshift */
1018c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1019c074d1c9Sdrahn 	 32,			/* bitsize */
1020c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1021c88b1d6cSniklas 	 0,			/* bitpos */
1022c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1023*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1024c88b1d6cSniklas 	 "R_MIPS_DELETE",	/* name */
1025c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1026c88b1d6cSniklas 	 0,			/* src_mask */
1027c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
1028c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1029c88b1d6cSniklas 
1030c88b1d6cSniklas   /* Get the higher value of a 64 bit addend.  */
1031c88b1d6cSniklas   HOWTO (R_MIPS_HIGHER,		/* type */
1032c88b1d6cSniklas 	 0,			/* rightshift */
1033c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1034c88b1d6cSniklas 	 16,			/* bitsize */
1035c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1036c88b1d6cSniklas 	 0,			/* bitpos */
1037c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1038*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1039c88b1d6cSniklas 	 "R_MIPS_HIGHER",	/* name */
1040c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1041c88b1d6cSniklas 	 0,			/* src_mask */
1042c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
1043c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1044c88b1d6cSniklas 
1045c88b1d6cSniklas   /* Get the highest value of a 64 bit addend.  */
1046c88b1d6cSniklas   HOWTO (R_MIPS_HIGHEST,	/* type */
1047c88b1d6cSniklas 	 0,			/* rightshift */
1048c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1049c88b1d6cSniklas 	 16,			/* bitsize */
1050c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1051c88b1d6cSniklas 	 0,			/* bitpos */
1052c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1053*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1054c88b1d6cSniklas 	 "R_MIPS_HIGHEST",	/* name */
1055c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1056c88b1d6cSniklas 	 0,			/* src_mask */
1057c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
1058c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1059c88b1d6cSniklas 
1060c88b1d6cSniklas   /* High 16 bits of displacement in global offset table.  */
1061c88b1d6cSniklas   HOWTO (R_MIPS_CALL_HI16,	/* type */
1062c88b1d6cSniklas 	 0,			/* rightshift */
1063c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1064c88b1d6cSniklas 	 16,			/* bitsize */
1065c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1066c88b1d6cSniklas 	 0,			/* bitpos */
1067c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1068*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1069c88b1d6cSniklas 	 "R_MIPS_CALL_HI16",	/* name */
1070c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1071c88b1d6cSniklas 	 0,			/* src_mask */
1072c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
1073c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1074c88b1d6cSniklas 
1075c88b1d6cSniklas   /* Low 16 bits of displacement in global offset table.  */
1076c88b1d6cSniklas   HOWTO (R_MIPS_CALL_LO16,	/* type */
1077c88b1d6cSniklas 	 0,			/* rightshift */
1078c88b1d6cSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1079c88b1d6cSniklas 	 16,			/* bitsize */
1080c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1081c88b1d6cSniklas 	 0,			/* bitpos */
1082c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1083*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1084c88b1d6cSniklas 	 "R_MIPS_CALL_LO16",	/* name */
1085c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1086c88b1d6cSniklas 	 0,			/* src_mask */
1087c88b1d6cSniklas 	 0x0000ffff,		/* dst_mask */
1088c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1089c88b1d6cSniklas 
1090c074d1c9Sdrahn   /* Section displacement, used by an associated event location section.  */
1091c88b1d6cSniklas   HOWTO (R_MIPS_SCN_DISP,	/* type */
1092c88b1d6cSniklas 	 0,			/* rightshift */
1093c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1094c074d1c9Sdrahn 	 32,			/* bitsize */
1095c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1096c88b1d6cSniklas 	 0,			/* bitpos */
1097c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1098*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1099c88b1d6cSniklas 	 "R_MIPS_SCN_DISP",	/* name */
1100c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1101c88b1d6cSniklas 	 0,			/* src_mask */
1102c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
1103c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1104c88b1d6cSniklas 
1105c88b1d6cSniklas   HOWTO (R_MIPS_REL16,		/* type */
1106c88b1d6cSniklas 	 0,			/* rightshift */
1107c074d1c9Sdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
1108c074d1c9Sdrahn 	 16,			/* bitsize */
1109c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1110c88b1d6cSniklas 	 0,			/* bitpos */
1111c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
1112*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1113c88b1d6cSniklas 	 "R_MIPS_REL16",	/* name */
1114c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1115c88b1d6cSniklas 	 0,			/* src_mask */
1116c074d1c9Sdrahn 	 0xffff,		/* dst_mask */
1117c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1118c88b1d6cSniklas 
1119c074d1c9Sdrahn   /* These two are obsolete.  */
1120c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
1121c074d1c9Sdrahn   EMPTY_HOWTO (R_MIPS_PJUMP),
1122c88b1d6cSniklas 
1123c074d1c9Sdrahn   /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section.
1124c074d1c9Sdrahn      It must be used for multigot GOT's (and only there).  */
1125c88b1d6cSniklas   HOWTO (R_MIPS_RELGOT,		/* type */
1126c88b1d6cSniklas 	 0,			/* rightshift */
1127c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1128c074d1c9Sdrahn 	 32,			/* bitsize */
1129c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1130c88b1d6cSniklas 	 0,			/* bitpos */
1131c88b1d6cSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1132*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1133c88b1d6cSniklas 	 "R_MIPS_RELGOT",	/* name */
1134c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1135c88b1d6cSniklas 	 0,			/* src_mask */
1136c074d1c9Sdrahn 	 0xffffffff,		/* dst_mask */
1137c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1138b305b0f1Sespie 
1139b305b0f1Sespie   /* Protected jump conversion.  This is an optimization hint.  No
1140b305b0f1Sespie      relocation is required for correctness.  */
1141b305b0f1Sespie   HOWTO (R_MIPS_JALR,	        /* type */
1142b305b0f1Sespie 	 0,			/* rightshift */
1143c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1144c074d1c9Sdrahn 	 32,			/* bitsize */
1145c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1146b305b0f1Sespie 	 0,			/* bitpos */
1147b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
1148*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1149b305b0f1Sespie 	 "R_MIPS_JALR",	        /* name */
1150c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1151c074d1c9Sdrahn 	 0,			/* src_mask */
1152b305b0f1Sespie 	 0x00000000,		/* dst_mask */
1153c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1154c88b1d6cSniklas };
1155c88b1d6cSniklas 
1156c074d1c9Sdrahn /* The reloc used for the mips16 jump instruction.  */
1157c074d1c9Sdrahn static reloc_howto_type elf_mips16_jump_howto =
1158c074d1c9Sdrahn   HOWTO (R_MIPS16_26,		/* type */
1159c074d1c9Sdrahn 	 2,			/* rightshift */
1160c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1161c074d1c9Sdrahn 	 26,			/* bitsize */
1162c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1163c074d1c9Sdrahn 	 0,			/* bitpos */
1164c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
1165c074d1c9Sdrahn 	 			/* This needs complex overflow
1166c074d1c9Sdrahn 				   detection, because the upper four
1167c074d1c9Sdrahn 				   bits must match the PC.  */
1168c074d1c9Sdrahn 	 mips16_jump_reloc,	/* special_function */
1169c074d1c9Sdrahn 	 "R_MIPS16_26",		/* name */
1170c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1171c074d1c9Sdrahn 	 0x3ffffff,		/* src_mask */
1172c074d1c9Sdrahn 	 0x3ffffff,		/* dst_mask */
1173c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
1174c074d1c9Sdrahn 
1175c074d1c9Sdrahn /* The reloc used for the mips16 gprel instruction.  */
1176c074d1c9Sdrahn static reloc_howto_type elf_mips16_gprel_howto =
1177c074d1c9Sdrahn   HOWTO (R_MIPS16_GPREL,	/* type */
1178c074d1c9Sdrahn 	 0,			/* rightshift */
1179c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1180c074d1c9Sdrahn 	 16,			/* bitsize */
1181c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1182c074d1c9Sdrahn 	 0,			/* bitpos */
1183c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
1184c074d1c9Sdrahn 	 mips16_gprel_reloc,	/* special_function */
1185c074d1c9Sdrahn 	 "R_MIPS16_GPREL",	/* name */
1186c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1187c074d1c9Sdrahn 	 0x07ff001f,		/* src_mask */
1188c074d1c9Sdrahn 	 0x07ff001f,	        /* dst_mask */
1189c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
1190c074d1c9Sdrahn 
1191c074d1c9Sdrahn /* GNU extension to record C++ vtable hierarchy */
1192c074d1c9Sdrahn static reloc_howto_type elf_mips_gnu_vtinherit_howto =
1193c074d1c9Sdrahn   HOWTO (R_MIPS_GNU_VTINHERIT,	/* type */
1194c074d1c9Sdrahn 	 0,			/* rightshift */
1195c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1196c074d1c9Sdrahn 	 0,			/* bitsize */
1197c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1198c074d1c9Sdrahn 	 0,			/* bitpos */
1199c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
1200c074d1c9Sdrahn 	 NULL,			/* special_function */
1201c074d1c9Sdrahn 	 "R_MIPS_GNU_VTINHERIT", /* name */
1202c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1203c074d1c9Sdrahn 	 0,			/* src_mask */
1204c074d1c9Sdrahn 	 0,			/* dst_mask */
1205c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
1206c074d1c9Sdrahn 
1207c074d1c9Sdrahn /* GNU extension to record C++ vtable member usage */
1208c074d1c9Sdrahn static reloc_howto_type elf_mips_gnu_vtentry_howto =
1209c074d1c9Sdrahn   HOWTO (R_MIPS_GNU_VTENTRY,	/* type */
1210c074d1c9Sdrahn 	 0,			/* rightshift */
1211c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1212c074d1c9Sdrahn 	 0,			/* bitsize */
1213c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1214c074d1c9Sdrahn 	 0,			/* bitpos */
1215c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
1216c074d1c9Sdrahn 	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
1217c074d1c9Sdrahn 	 "R_MIPS_GNU_VTENTRY",	/* name */
1218c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1219c074d1c9Sdrahn 	 0,			/* src_mask */
1220c074d1c9Sdrahn 	 0,			/* dst_mask */
1221c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
1222c074d1c9Sdrahn 
1223*007c2a45Smiod /* 16 bit offset for pc-relative branches.  */
1224*007c2a45Smiod static reloc_howto_type elf_mips_gnu_rel16_s2 =
1225*007c2a45Smiod   HOWTO (R_MIPS_GNU_REL16_S2,	/* type */
1226*007c2a45Smiod 	 2,			/* rightshift */
1227*007c2a45Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1228*007c2a45Smiod 	 16,			/* bitsize */
1229*007c2a45Smiod 	 TRUE,			/* pc_relative */
1230*007c2a45Smiod 	 0,			/* bitpos */
1231*007c2a45Smiod 	 complain_overflow_signed, /* complain_on_overflow */
1232*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1233*007c2a45Smiod 	 "R_MIPS_GNU_REL16_S2",	/* name */
1234*007c2a45Smiod 	 TRUE,			/* partial_inplace */
1235*007c2a45Smiod 	 0x0000ffff,		/* src_mask */
1236*007c2a45Smiod 	 0x0000ffff,		/* dst_mask */
1237*007c2a45Smiod 	 TRUE);			/* pcrel_offset */
1238*007c2a45Smiod 
1239*007c2a45Smiod /* 16 bit offset for pc-relative branches.  */
1240*007c2a45Smiod static reloc_howto_type elf_mips_gnu_rela16_s2 =
1241*007c2a45Smiod   HOWTO (R_MIPS_GNU_REL16_S2,	/* type */
1242*007c2a45Smiod 	 2,			/* rightshift */
1243*007c2a45Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1244*007c2a45Smiod 	 16,			/* bitsize */
1245*007c2a45Smiod 	 TRUE,			/* pc_relative */
1246*007c2a45Smiod 	 0,			/* bitpos */
1247*007c2a45Smiod 	 complain_overflow_signed, /* complain_on_overflow */
1248*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc,	/* special_function */
1249*007c2a45Smiod 	 "R_MIPS_GNU_REL16_S2",	/* name */
1250*007c2a45Smiod 	 FALSE,			/* partial_inplace */
1251*007c2a45Smiod 	 0,			/* src_mask */
1252*007c2a45Smiod 	 0x0000ffff,		/* dst_mask */
1253*007c2a45Smiod 	 TRUE);			/* pcrel_offset */
1254*007c2a45Smiod 
1255c88b1d6cSniklas /* Swap in a MIPS 64-bit Rel reloc.  */
1256c88b1d6cSniklas 
1257c88b1d6cSniklas static void
mips_elf64_swap_reloc_in(bfd * abfd,const Elf64_Mips_External_Rel * src,Elf64_Mips_Internal_Rela * dst)1258*007c2a45Smiod mips_elf64_swap_reloc_in (bfd *abfd, const Elf64_Mips_External_Rel *src,
1259*007c2a45Smiod 			  Elf64_Mips_Internal_Rela *dst)
1260c88b1d6cSniklas {
1261c074d1c9Sdrahn   dst->r_offset = H_GET_64 (abfd, src->r_offset);
1262c074d1c9Sdrahn   dst->r_sym = H_GET_32 (abfd, src->r_sym);
1263c074d1c9Sdrahn   dst->r_ssym = H_GET_8 (abfd, src->r_ssym);
1264c074d1c9Sdrahn   dst->r_type3 = H_GET_8 (abfd, src->r_type3);
1265c074d1c9Sdrahn   dst->r_type2 = H_GET_8 (abfd, src->r_type2);
1266c074d1c9Sdrahn   dst->r_type = H_GET_8 (abfd, src->r_type);
1267c074d1c9Sdrahn   dst->r_addend = 0;
1268c88b1d6cSniklas }
1269c88b1d6cSniklas 
1270c88b1d6cSniklas /* Swap in a MIPS 64-bit Rela reloc.  */
1271c88b1d6cSniklas 
1272c88b1d6cSniklas static void
mips_elf64_swap_reloca_in(bfd * abfd,const Elf64_Mips_External_Rela * src,Elf64_Mips_Internal_Rela * dst)1273*007c2a45Smiod mips_elf64_swap_reloca_in (bfd *abfd, const Elf64_Mips_External_Rela *src,
1274*007c2a45Smiod 			   Elf64_Mips_Internal_Rela *dst)
1275c88b1d6cSniklas {
1276c074d1c9Sdrahn   dst->r_offset = H_GET_64 (abfd, src->r_offset);
1277c074d1c9Sdrahn   dst->r_sym = H_GET_32 (abfd, src->r_sym);
1278c074d1c9Sdrahn   dst->r_ssym = H_GET_8 (abfd, src->r_ssym);
1279c074d1c9Sdrahn   dst->r_type3 = H_GET_8 (abfd, src->r_type3);
1280c074d1c9Sdrahn   dst->r_type2 = H_GET_8 (abfd, src->r_type2);
1281c074d1c9Sdrahn   dst->r_type = H_GET_8 (abfd, src->r_type);
1282c074d1c9Sdrahn   dst->r_addend = H_GET_S64 (abfd, src->r_addend);
1283c88b1d6cSniklas }
1284c88b1d6cSniklas 
1285c88b1d6cSniklas /* Swap out a MIPS 64-bit Rel reloc.  */
1286c88b1d6cSniklas 
1287c88b1d6cSniklas static void
mips_elf64_swap_reloc_out(bfd * abfd,const Elf64_Mips_Internal_Rela * src,Elf64_Mips_External_Rel * dst)1288*007c2a45Smiod mips_elf64_swap_reloc_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src,
1289*007c2a45Smiod 			   Elf64_Mips_External_Rel *dst)
1290c88b1d6cSniklas {
1291c074d1c9Sdrahn   H_PUT_64 (abfd, src->r_offset, dst->r_offset);
1292c074d1c9Sdrahn   H_PUT_32 (abfd, src->r_sym, dst->r_sym);
1293c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
1294c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type3, dst->r_type3);
1295c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type2, dst->r_type2);
1296c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type, dst->r_type);
1297c88b1d6cSniklas }
1298c88b1d6cSniklas 
1299c88b1d6cSniklas /* Swap out a MIPS 64-bit Rela reloc.  */
1300c88b1d6cSniklas 
1301c88b1d6cSniklas static void
mips_elf64_swap_reloca_out(bfd * abfd,const Elf64_Mips_Internal_Rela * src,Elf64_Mips_External_Rela * dst)1302*007c2a45Smiod mips_elf64_swap_reloca_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src,
1303*007c2a45Smiod 			    Elf64_Mips_External_Rela *dst)
1304c88b1d6cSniklas {
1305c074d1c9Sdrahn   H_PUT_64 (abfd, src->r_offset, dst->r_offset);
1306c074d1c9Sdrahn   H_PUT_32 (abfd, src->r_sym, dst->r_sym);
1307c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
1308c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type3, dst->r_type3);
1309c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type2, dst->r_type2);
1310c074d1c9Sdrahn   H_PUT_8 (abfd, src->r_type, dst->r_type);
1311c074d1c9Sdrahn   H_PUT_S64 (abfd, src->r_addend, dst->r_addend);
1312b305b0f1Sespie }
1313b305b0f1Sespie 
1314b305b0f1Sespie /* Swap in a MIPS 64-bit Rel reloc.  */
1315b305b0f1Sespie 
1316b305b0f1Sespie static void
mips_elf64_be_swap_reloc_in(bfd * abfd,const bfd_byte * src,Elf_Internal_Rela * dst)1317*007c2a45Smiod mips_elf64_be_swap_reloc_in (bfd *abfd, const bfd_byte *src,
1318*007c2a45Smiod 			     Elf_Internal_Rela *dst)
1319b305b0f1Sespie {
1320c074d1c9Sdrahn   Elf64_Mips_Internal_Rela mirel;
1321b305b0f1Sespie 
1322b305b0f1Sespie   mips_elf64_swap_reloc_in (abfd,
1323b305b0f1Sespie 			    (const Elf64_Mips_External_Rel *) src,
1324b305b0f1Sespie 			    &mirel);
1325b305b0f1Sespie 
1326b305b0f1Sespie   dst[0].r_offset = mirel.r_offset;
1327c074d1c9Sdrahn   dst[0].r_info = ELF64_R_INFO (mirel.r_sym, mirel.r_type);
1328c074d1c9Sdrahn   dst[0].r_addend = 0;
1329b305b0f1Sespie   dst[1].r_offset = mirel.r_offset;
1330c074d1c9Sdrahn   dst[1].r_info = ELF64_R_INFO (mirel.r_ssym, mirel.r_type2);
1331c074d1c9Sdrahn   dst[1].r_addend = 0;
1332b305b0f1Sespie   dst[2].r_offset = mirel.r_offset;
1333c074d1c9Sdrahn   dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirel.r_type3);
1334c074d1c9Sdrahn   dst[2].r_addend = 0;
1335b305b0f1Sespie }
1336b305b0f1Sespie 
1337b305b0f1Sespie /* Swap in a MIPS 64-bit Rela reloc.  */
1338b305b0f1Sespie 
1339b305b0f1Sespie static void
mips_elf64_be_swap_reloca_in(bfd * abfd,const bfd_byte * src,Elf_Internal_Rela * dst)1340*007c2a45Smiod mips_elf64_be_swap_reloca_in (bfd *abfd, const bfd_byte *src,
1341*007c2a45Smiod 			      Elf_Internal_Rela *dst)
1342b305b0f1Sespie {
1343b305b0f1Sespie   Elf64_Mips_Internal_Rela mirela;
1344b305b0f1Sespie 
1345b305b0f1Sespie   mips_elf64_swap_reloca_in (abfd,
1346b305b0f1Sespie 			     (const Elf64_Mips_External_Rela *) src,
1347b305b0f1Sespie 			     &mirela);
1348b305b0f1Sespie 
1349b305b0f1Sespie   dst[0].r_offset = mirela.r_offset;
1350c074d1c9Sdrahn   dst[0].r_info = ELF64_R_INFO (mirela.r_sym, mirela.r_type);
1351b305b0f1Sespie   dst[0].r_addend = mirela.r_addend;
1352b305b0f1Sespie   dst[1].r_offset = mirela.r_offset;
1353c074d1c9Sdrahn   dst[1].r_info = ELF64_R_INFO (mirela.r_ssym, mirela.r_type2);
1354b305b0f1Sespie   dst[1].r_addend = 0;
1355b305b0f1Sespie   dst[2].r_offset = mirela.r_offset;
1356c074d1c9Sdrahn   dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirela.r_type3);
1357b305b0f1Sespie   dst[2].r_addend = 0;
1358b305b0f1Sespie }
1359b305b0f1Sespie 
1360b305b0f1Sespie /* Swap out a MIPS 64-bit Rel reloc.  */
1361b305b0f1Sespie 
1362b305b0f1Sespie static void
mips_elf64_be_swap_reloc_out(bfd * abfd,const Elf_Internal_Rela * src,bfd_byte * dst)1363*007c2a45Smiod mips_elf64_be_swap_reloc_out (bfd *abfd, const Elf_Internal_Rela *src,
1364*007c2a45Smiod 			      bfd_byte *dst)
1365b305b0f1Sespie {
1366c074d1c9Sdrahn   Elf64_Mips_Internal_Rela mirel;
1367b305b0f1Sespie 
1368c074d1c9Sdrahn   mirel.r_offset = src[0].r_offset;
1369c074d1c9Sdrahn   BFD_ASSERT(src[0].r_offset == src[1].r_offset);
1370c074d1c9Sdrahn #if 0
1371c074d1c9Sdrahn   BFD_ASSERT(src[0].r_offset == src[2].r_offset);
1372c074d1c9Sdrahn #endif
1373c074d1c9Sdrahn 
1374c074d1c9Sdrahn   mirel.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
1375c074d1c9Sdrahn   mirel.r_sym = ELF64_R_SYM (src[0].r_info);
1376c074d1c9Sdrahn   mirel.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info);
1377c074d1c9Sdrahn   mirel.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
1378c074d1c9Sdrahn   mirel.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info);
1379b305b0f1Sespie 
1380b305b0f1Sespie   mips_elf64_swap_reloc_out (abfd, &mirel,
1381b305b0f1Sespie 			     (Elf64_Mips_External_Rel *) dst);
1382b305b0f1Sespie }
1383b305b0f1Sespie 
1384b305b0f1Sespie /* Swap out a MIPS 64-bit Rela reloc.  */
1385b305b0f1Sespie 
1386b305b0f1Sespie static void
mips_elf64_be_swap_reloca_out(bfd * abfd,const Elf_Internal_Rela * src,bfd_byte * dst)1387*007c2a45Smiod mips_elf64_be_swap_reloca_out (bfd *abfd, const Elf_Internal_Rela *src,
1388*007c2a45Smiod 			       bfd_byte *dst)
1389b305b0f1Sespie {
1390b305b0f1Sespie   Elf64_Mips_Internal_Rela mirela;
1391b305b0f1Sespie 
1392c074d1c9Sdrahn   mirela.r_offset = src[0].r_offset;
1393c074d1c9Sdrahn   BFD_ASSERT(src[0].r_offset == src[1].r_offset);
1394c074d1c9Sdrahn   BFD_ASSERT(src[0].r_offset == src[2].r_offset);
1395c074d1c9Sdrahn 
1396c074d1c9Sdrahn   mirela.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
1397c074d1c9Sdrahn   mirela.r_sym = ELF64_R_SYM (src[0].r_info);
1398c074d1c9Sdrahn   mirela.r_addend = src[0].r_addend;
1399c074d1c9Sdrahn   BFD_ASSERT(src[1].r_addend == 0);
1400c074d1c9Sdrahn   BFD_ASSERT(src[2].r_addend == 0);
1401c074d1c9Sdrahn 
1402c074d1c9Sdrahn   mirela.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info);
1403c074d1c9Sdrahn   mirela.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
1404c074d1c9Sdrahn   mirela.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info);
1405b305b0f1Sespie 
1406b305b0f1Sespie   mips_elf64_swap_reloca_out (abfd, &mirela,
1407b305b0f1Sespie 			      (Elf64_Mips_External_Rela *) dst);
1408c88b1d6cSniklas }
1409c074d1c9Sdrahn 
1410c074d1c9Sdrahn /* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
1411c074d1c9Sdrahn    dangerous relocation.  */
1412c074d1c9Sdrahn 
1413c074d1c9Sdrahn static bfd_boolean
mips_elf64_assign_gp(bfd * output_bfd,bfd_vma * pgp)1414*007c2a45Smiod mips_elf64_assign_gp (bfd *output_bfd, bfd_vma *pgp)
1415c074d1c9Sdrahn {
1416c074d1c9Sdrahn   unsigned int count;
1417c074d1c9Sdrahn   asymbol **sym;
1418c074d1c9Sdrahn   unsigned int i;
1419c074d1c9Sdrahn 
1420c074d1c9Sdrahn   /* If we've already figured out what GP will be, just return it.  */
1421c074d1c9Sdrahn   *pgp = _bfd_get_gp_value (output_bfd);
1422c074d1c9Sdrahn   if (*pgp)
1423c074d1c9Sdrahn     return TRUE;
1424c074d1c9Sdrahn 
1425c074d1c9Sdrahn   count = bfd_get_symcount (output_bfd);
1426c074d1c9Sdrahn   sym = bfd_get_outsymbols (output_bfd);
1427c074d1c9Sdrahn 
1428c074d1c9Sdrahn   /* The linker script will have created a symbol named `_gp' with the
1429c074d1c9Sdrahn      appropriate value.  */
1430*007c2a45Smiod   if (sym == NULL)
1431c074d1c9Sdrahn     i = count;
1432c074d1c9Sdrahn   else
1433c074d1c9Sdrahn     {
1434c074d1c9Sdrahn       for (i = 0; i < count; i++, sym++)
1435c074d1c9Sdrahn 	{
1436c074d1c9Sdrahn 	  register const char *name;
1437c074d1c9Sdrahn 
1438c074d1c9Sdrahn 	  name = bfd_asymbol_name (*sym);
1439c074d1c9Sdrahn 	  if (*name == '_' && strcmp (name, "_gp") == 0)
1440c074d1c9Sdrahn 	    {
1441c074d1c9Sdrahn 	      *pgp = bfd_asymbol_value (*sym);
1442c074d1c9Sdrahn 	      _bfd_set_gp_value (output_bfd, *pgp);
1443c074d1c9Sdrahn 	      break;
1444c074d1c9Sdrahn 	    }
1445c074d1c9Sdrahn 	}
1446c074d1c9Sdrahn     }
1447c074d1c9Sdrahn 
1448c074d1c9Sdrahn   if (i >= count)
1449c074d1c9Sdrahn     {
1450c074d1c9Sdrahn       /* Only get the error once.  */
1451c074d1c9Sdrahn       *pgp = 4;
1452c074d1c9Sdrahn       _bfd_set_gp_value (output_bfd, *pgp);
1453c074d1c9Sdrahn       return FALSE;
1454c074d1c9Sdrahn     }
1455c074d1c9Sdrahn 
1456c074d1c9Sdrahn   return TRUE;
1457c074d1c9Sdrahn }
1458c074d1c9Sdrahn 
1459c074d1c9Sdrahn /* We have to figure out the gp value, so that we can adjust the
1460c074d1c9Sdrahn    symbol value correctly.  We look up the symbol _gp in the output
1461c074d1c9Sdrahn    BFD.  If we can't find it, we're stuck.  We cache it in the ELF
1462c074d1c9Sdrahn    target data.  We don't need to adjust the symbol value for an
1463*007c2a45Smiod    external symbol if we are producing relocatable output.  */
1464c074d1c9Sdrahn 
1465c074d1c9Sdrahn static bfd_reloc_status_type
mips_elf64_final_gp(bfd * output_bfd,asymbol * symbol,bfd_boolean relocatable,char ** error_message,bfd_vma * pgp)1466*007c2a45Smiod mips_elf64_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
1467*007c2a45Smiod 		     char **error_message, bfd_vma *pgp)
1468c074d1c9Sdrahn {
1469c074d1c9Sdrahn   if (bfd_is_und_section (symbol->section)
1470*007c2a45Smiod       && ! relocatable)
1471c074d1c9Sdrahn     {
1472c074d1c9Sdrahn       *pgp = 0;
1473c074d1c9Sdrahn       return bfd_reloc_undefined;
1474c074d1c9Sdrahn     }
1475c074d1c9Sdrahn 
1476c074d1c9Sdrahn   *pgp = _bfd_get_gp_value (output_bfd);
1477c074d1c9Sdrahn   if (*pgp == 0
1478*007c2a45Smiod       && (! relocatable
1479c074d1c9Sdrahn 	  || (symbol->flags & BSF_SECTION_SYM) != 0))
1480c074d1c9Sdrahn     {
1481*007c2a45Smiod       if (relocatable)
1482c074d1c9Sdrahn 	{
1483c074d1c9Sdrahn 	  /* Make up a value.  */
1484c074d1c9Sdrahn 	  *pgp = symbol->section->output_section->vma /*+ 0x4000*/;
1485c074d1c9Sdrahn 	  _bfd_set_gp_value (output_bfd, *pgp);
1486c074d1c9Sdrahn 	}
1487c074d1c9Sdrahn       else if (!mips_elf64_assign_gp (output_bfd, pgp))
1488c074d1c9Sdrahn 	{
1489c074d1c9Sdrahn 	  *error_message =
1490c074d1c9Sdrahn 	    (char *) _("GP relative relocation when _gp not defined");
1491c074d1c9Sdrahn 	  return bfd_reloc_dangerous;
1492c074d1c9Sdrahn 	}
1493c074d1c9Sdrahn     }
1494c074d1c9Sdrahn 
1495c074d1c9Sdrahn   return bfd_reloc_ok;
1496c074d1c9Sdrahn }
1497c074d1c9Sdrahn 
1498c074d1c9Sdrahn /* Do a R_MIPS_GPREL16 relocation.  This is a 16 bit value which must
1499c074d1c9Sdrahn    become the offset from the gp register.  */
1500c074d1c9Sdrahn 
1501c074d1c9Sdrahn static bfd_reloc_status_type
mips_elf64_gprel16_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)1502*007c2a45Smiod mips_elf64_gprel16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1503*007c2a45Smiod 			  void *data, asection *input_section, bfd *output_bfd,
1504*007c2a45Smiod 			  char **error_message)
1505c074d1c9Sdrahn {
1506*007c2a45Smiod   bfd_boolean relocatable;
1507c074d1c9Sdrahn   bfd_reloc_status_type ret;
1508c074d1c9Sdrahn   bfd_vma gp;
1509c074d1c9Sdrahn 
1510*007c2a45Smiod   /* If we're relocating, and this is an external symbol, we don't want
1511*007c2a45Smiod      to change anything.  */
1512*007c2a45Smiod   if (output_bfd != NULL
1513c074d1c9Sdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
1514*007c2a45Smiod       && (symbol->flags & BSF_LOCAL) != 0)
1515c074d1c9Sdrahn     {
1516c074d1c9Sdrahn       reloc_entry->address += input_section->output_offset;
1517c074d1c9Sdrahn       return bfd_reloc_ok;
1518c074d1c9Sdrahn     }
1519c074d1c9Sdrahn 
1520*007c2a45Smiod   if (output_bfd != NULL)
1521*007c2a45Smiod     relocatable = TRUE;
1522c074d1c9Sdrahn   else
1523c074d1c9Sdrahn     {
1524*007c2a45Smiod       relocatable = FALSE;
1525c074d1c9Sdrahn       output_bfd = symbol->section->output_section->owner;
1526c074d1c9Sdrahn     }
1527c074d1c9Sdrahn 
1528*007c2a45Smiod   ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
1529c074d1c9Sdrahn 			     &gp);
1530c074d1c9Sdrahn   if (ret != bfd_reloc_ok)
1531c074d1c9Sdrahn     return ret;
1532c074d1c9Sdrahn 
1533c074d1c9Sdrahn   return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
1534*007c2a45Smiod 					input_section, relocatable,
1535c074d1c9Sdrahn 					data, gp);
1536c074d1c9Sdrahn }
1537c074d1c9Sdrahn 
1538c074d1c9Sdrahn /* Do a R_MIPS_LITERAL relocation.  */
1539c074d1c9Sdrahn 
1540c074d1c9Sdrahn static bfd_reloc_status_type
mips_elf64_literal_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)1541*007c2a45Smiod mips_elf64_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1542*007c2a45Smiod 			  void *data, asection *input_section, bfd *output_bfd,
1543*007c2a45Smiod 			  char **error_message)
1544c074d1c9Sdrahn {
1545*007c2a45Smiod   bfd_boolean relocatable;
1546c074d1c9Sdrahn   bfd_reloc_status_type ret;
1547c074d1c9Sdrahn   bfd_vma gp;
1548c074d1c9Sdrahn 
1549c074d1c9Sdrahn   /* If we're relocating, and this is an external symbol, we don't
1550c074d1c9Sdrahn      want to change anything.  */
1551*007c2a45Smiod   if (output_bfd != NULL
1552c074d1c9Sdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
1553*007c2a45Smiod       && (symbol->flags & BSF_LOCAL) != 0)
1554c074d1c9Sdrahn     {
1555c074d1c9Sdrahn       reloc_entry->address += input_section->output_offset;
1556c074d1c9Sdrahn       return bfd_reloc_ok;
1557c074d1c9Sdrahn     }
1558c074d1c9Sdrahn 
1559c074d1c9Sdrahn   /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.  */
1560*007c2a45Smiod   if (output_bfd != NULL)
1561*007c2a45Smiod     relocatable = TRUE;
1562c074d1c9Sdrahn   else
1563c074d1c9Sdrahn     {
1564*007c2a45Smiod       relocatable = FALSE;
1565c074d1c9Sdrahn       output_bfd = symbol->section->output_section->owner;
1566c074d1c9Sdrahn     }
1567c074d1c9Sdrahn 
1568*007c2a45Smiod   ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
1569c074d1c9Sdrahn 			     &gp);
1570c074d1c9Sdrahn   if (ret != bfd_reloc_ok)
1571c074d1c9Sdrahn     return ret;
1572c074d1c9Sdrahn 
1573c074d1c9Sdrahn   return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
1574*007c2a45Smiod 					input_section, relocatable,
1575c074d1c9Sdrahn 					data, gp);
1576c074d1c9Sdrahn }
1577c074d1c9Sdrahn 
1578c074d1c9Sdrahn /* Do a R_MIPS_GPREL32 relocation.  This is a 32 bit value which must
1579c074d1c9Sdrahn    become the offset from the gp register.  */
1580c074d1c9Sdrahn 
1581c074d1c9Sdrahn static bfd_reloc_status_type
mips_elf64_gprel32_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)1582*007c2a45Smiod mips_elf64_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1583*007c2a45Smiod 			  void *data, asection *input_section, bfd *output_bfd,
1584*007c2a45Smiod 			  char **error_message)
1585c074d1c9Sdrahn {
1586*007c2a45Smiod   bfd_boolean relocatable;
1587c074d1c9Sdrahn   bfd_reloc_status_type ret;
1588c074d1c9Sdrahn   bfd_vma gp;
1589c074d1c9Sdrahn   bfd_vma relocation;
1590*007c2a45Smiod   bfd_vma val;
1591c074d1c9Sdrahn 
1592*007c2a45Smiod   /* If we're relocating, and this is an external symbol, we don't want
1593*007c2a45Smiod      to change anything.  */
1594*007c2a45Smiod   if (output_bfd != NULL
1595c074d1c9Sdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
1596*007c2a45Smiod       && (symbol->flags & BSF_LOCAL) != 0)
1597c074d1c9Sdrahn     {
1598c074d1c9Sdrahn       *error_message = (char *)
1599c074d1c9Sdrahn 	_("32bits gp relative relocation occurs for an external symbol");
1600c074d1c9Sdrahn       return bfd_reloc_outofrange;
1601c074d1c9Sdrahn     }
1602c074d1c9Sdrahn 
1603*007c2a45Smiod   if (output_bfd != NULL)
1604*007c2a45Smiod     relocatable = TRUE;
1605c074d1c9Sdrahn   else
1606c074d1c9Sdrahn     {
1607*007c2a45Smiod       relocatable = FALSE;
1608c074d1c9Sdrahn       output_bfd = symbol->section->output_section->owner;
1609*007c2a45Smiod     }
1610c074d1c9Sdrahn 
1611*007c2a45Smiod     ret = mips_elf64_final_gp (output_bfd, symbol, relocatable,
1612c074d1c9Sdrahn 			       error_message, &gp);
1613c074d1c9Sdrahn     if (ret != bfd_reloc_ok)
1614c074d1c9Sdrahn       return ret;
1615c074d1c9Sdrahn 
1616c074d1c9Sdrahn   if (bfd_is_com_section (symbol->section))
1617c074d1c9Sdrahn     relocation = 0;
1618c074d1c9Sdrahn   else
1619c074d1c9Sdrahn     relocation = symbol->value;
1620c074d1c9Sdrahn 
1621c074d1c9Sdrahn   relocation += symbol->section->output_section->vma;
1622c074d1c9Sdrahn   relocation += symbol->section->output_offset;
1623c074d1c9Sdrahn 
1624c074d1c9Sdrahn   if (reloc_entry->address > input_section->_cooked_size)
1625c074d1c9Sdrahn     return bfd_reloc_outofrange;
1626c074d1c9Sdrahn 
1627c074d1c9Sdrahn   /* Set val to the offset into the section or symbol.  */
1628*007c2a45Smiod   val = reloc_entry->addend;
1629*007c2a45Smiod 
1630*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1631*007c2a45Smiod     val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
1632c074d1c9Sdrahn 
1633c074d1c9Sdrahn   /* Adjust val for the final section location and GP value.  If we
1634*007c2a45Smiod      are producing relocatable output, we don't want to do this for
1635c074d1c9Sdrahn      an external symbol.  */
1636*007c2a45Smiod   if (! relocatable
1637c074d1c9Sdrahn       || (symbol->flags & BSF_SECTION_SYM) != 0)
1638c074d1c9Sdrahn     val += relocation - gp;
1639c074d1c9Sdrahn 
1640*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1641c074d1c9Sdrahn     bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
1642*007c2a45Smiod   else
1643*007c2a45Smiod     reloc_entry->addend = val;
1644c074d1c9Sdrahn 
1645*007c2a45Smiod   if (relocatable)
1646c074d1c9Sdrahn     reloc_entry->address += input_section->output_offset;
1647c074d1c9Sdrahn 
1648c074d1c9Sdrahn   return bfd_reloc_ok;
1649c074d1c9Sdrahn }
1650c074d1c9Sdrahn 
1651c074d1c9Sdrahn /* Do a R_MIPS_SHIFT6 relocation. The MSB of the shift is stored at bit 2,
1652c074d1c9Sdrahn    the rest is at bits 6-10. The bitpos already got right by the howto.  */
1653c074d1c9Sdrahn 
1654c074d1c9Sdrahn static bfd_reloc_status_type
mips_elf64_shift6_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)1655*007c2a45Smiod mips_elf64_shift6_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1656*007c2a45Smiod 			 void *data, asection *input_section, bfd *output_bfd,
1657*007c2a45Smiod 			 char **error_message)
1658c074d1c9Sdrahn {
1659*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1660c074d1c9Sdrahn     {
1661*007c2a45Smiod       reloc_entry->addend = ((reloc_entry->addend & 0x00007c0)
1662*007c2a45Smiod 			     | (reloc_entry->addend & 0x00000800) >> 9);
1663c074d1c9Sdrahn     }
1664c074d1c9Sdrahn 
1665*007c2a45Smiod   return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
1666*007c2a45Smiod 				      input_section, output_bfd,
1667*007c2a45Smiod 				      error_message);
1668c074d1c9Sdrahn }
1669c074d1c9Sdrahn 
1670c074d1c9Sdrahn /* Handle a mips16 jump.  */
1671c074d1c9Sdrahn 
1672c074d1c9Sdrahn static bfd_reloc_status_type
mips16_jump_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry,asymbol * symbol,void * data ATTRIBUTE_UNUSED,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)1673*007c2a45Smiod mips16_jump_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
1674*007c2a45Smiod 		   asymbol *symbol, void *data ATTRIBUTE_UNUSED,
1675*007c2a45Smiod 		   asection *input_section, bfd *output_bfd,
1676*007c2a45Smiod 		   char **error_message ATTRIBUTE_UNUSED)
1677c074d1c9Sdrahn {
1678*007c2a45Smiod   if (output_bfd != NULL
1679c074d1c9Sdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
1680c074d1c9Sdrahn       && (! reloc_entry->howto->partial_inplace
1681c074d1c9Sdrahn 	  || reloc_entry->addend == 0))
1682c074d1c9Sdrahn     {
1683c074d1c9Sdrahn       reloc_entry->address += input_section->output_offset;
1684c074d1c9Sdrahn       return bfd_reloc_ok;
1685c074d1c9Sdrahn     }
1686c074d1c9Sdrahn 
1687c074d1c9Sdrahn   /* FIXME.  */
1688c074d1c9Sdrahn   {
1689c074d1c9Sdrahn     static bfd_boolean warned;
1690c074d1c9Sdrahn 
1691c074d1c9Sdrahn     if (! warned)
1692c074d1c9Sdrahn       (*_bfd_error_handler)
1693c074d1c9Sdrahn 	(_("Linking mips16 objects into %s format is not supported"),
1694c074d1c9Sdrahn 	 bfd_get_target (input_section->output_section->owner));
1695c074d1c9Sdrahn     warned = TRUE;
1696c074d1c9Sdrahn   }
1697c074d1c9Sdrahn 
1698c074d1c9Sdrahn   return bfd_reloc_undefined;
1699c074d1c9Sdrahn }
1700c074d1c9Sdrahn 
1701c074d1c9Sdrahn /* Handle a mips16 GP relative reloc.  */
1702c074d1c9Sdrahn 
1703c074d1c9Sdrahn static bfd_reloc_status_type
mips16_gprel_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)1704*007c2a45Smiod mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1705*007c2a45Smiod 		    void *data, asection *input_section, bfd *output_bfd,
1706*007c2a45Smiod 		    char **error_message)
1707c074d1c9Sdrahn {
1708*007c2a45Smiod   bfd_boolean relocatable;
1709c074d1c9Sdrahn   bfd_reloc_status_type ret;
1710c074d1c9Sdrahn   bfd_vma gp;
1711*007c2a45Smiod   unsigned short extend = 0;
1712*007c2a45Smiod   unsigned short insn = 0;
1713*007c2a45Smiod   bfd_signed_vma val;
1714*007c2a45Smiod   bfd_vma relocation;
1715c074d1c9Sdrahn 
1716c074d1c9Sdrahn   /* If we're relocating, and this is an external symbol with no
1717*007c2a45Smiod      addend, we don't want to change anything.  */
1718c074d1c9Sdrahn   if (output_bfd != NULL
1719c074d1c9Sdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
1720*007c2a45Smiod       && (symbol->flags & BSF_LOCAL) != 0)
1721c074d1c9Sdrahn     {
1722c074d1c9Sdrahn       reloc_entry->address += input_section->output_offset;
1723c074d1c9Sdrahn       return bfd_reloc_ok;
1724c074d1c9Sdrahn     }
1725c074d1c9Sdrahn 
1726c074d1c9Sdrahn   if (output_bfd != NULL)
1727*007c2a45Smiod     relocatable = TRUE;
1728c074d1c9Sdrahn   else
1729c074d1c9Sdrahn     {
1730*007c2a45Smiod       relocatable = FALSE;
1731c074d1c9Sdrahn       output_bfd = symbol->section->output_section->owner;
1732c074d1c9Sdrahn     }
1733c074d1c9Sdrahn 
1734*007c2a45Smiod   ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
1735c074d1c9Sdrahn 			     &gp);
1736c074d1c9Sdrahn   if (ret != bfd_reloc_ok)
1737c074d1c9Sdrahn     return ret;
1738c074d1c9Sdrahn 
1739c074d1c9Sdrahn   if (reloc_entry->address > input_section->_cooked_size)
1740c074d1c9Sdrahn     return bfd_reloc_outofrange;
1741c074d1c9Sdrahn 
1742*007c2a45Smiod   if (bfd_is_com_section (symbol->section))
1743*007c2a45Smiod     relocation = 0;
1744*007c2a45Smiod   else
1745*007c2a45Smiod     relocation = symbol->value;
1746*007c2a45Smiod 
1747*007c2a45Smiod   relocation += symbol->section->output_section->vma;
1748*007c2a45Smiod   relocation += symbol->section->output_offset;
1749*007c2a45Smiod 
1750*007c2a45Smiod   /* Set val to the offset into the section or symbol.  */
1751*007c2a45Smiod   val = reloc_entry->addend;
1752*007c2a45Smiod 
1753*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1754*007c2a45Smiod     {
1755c074d1c9Sdrahn       /* Pick up the mips16 extend instruction and the real instruction.  */
1756c074d1c9Sdrahn       extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
1757c074d1c9Sdrahn       insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
1758*007c2a45Smiod       val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
1759*007c2a45Smiod     }
1760c074d1c9Sdrahn 
1761*007c2a45Smiod   _bfd_mips_elf_sign_extend(val, 16);
1762c074d1c9Sdrahn 
1763*007c2a45Smiod   /* Adjust val for the final section location and GP value.  If we
1764*007c2a45Smiod      are producing relocatable output, we don't want to do this for
1765*007c2a45Smiod      an external symbol.  */
1766*007c2a45Smiod   if (! relocatable
1767*007c2a45Smiod       || (symbol->flags & BSF_SECTION_SYM) != 0)
1768*007c2a45Smiod     val += relocation - gp;
1769c074d1c9Sdrahn 
1770*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1771*007c2a45Smiod     {
1772c074d1c9Sdrahn       bfd_put_16 (abfd,
1773*007c2a45Smiod 		  (extend & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0),
1774c074d1c9Sdrahn 		  (bfd_byte *) data + reloc_entry->address);
1775c074d1c9Sdrahn       bfd_put_16 (abfd,
1776*007c2a45Smiod 		  (insn & 0xffe0) | (val & 0x1f),
1777c074d1c9Sdrahn 		  (bfd_byte *) data + reloc_entry->address + 2);
1778*007c2a45Smiod     }
1779*007c2a45Smiod   else
1780*007c2a45Smiod     reloc_entry->addend = val;
1781c074d1c9Sdrahn 
1782*007c2a45Smiod   if (relocatable)
1783*007c2a45Smiod     reloc_entry->address += input_section->output_offset;
1784*007c2a45Smiod   else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0))
1785*007c2a45Smiod     return bfd_reloc_overflow;
1786*007c2a45Smiod 
1787*007c2a45Smiod   return bfd_reloc_ok;
1788c074d1c9Sdrahn }
1789c074d1c9Sdrahn 
1790c88b1d6cSniklas /* A mapping from BFD reloc types to MIPS ELF reloc types.  */
1791c88b1d6cSniklas 
1792c074d1c9Sdrahn struct elf_reloc_map {
1793c074d1c9Sdrahn   bfd_reloc_code_real_type bfd_val;
1794c074d1c9Sdrahn   enum elf_mips_reloc_type elf_val;
1795c88b1d6cSniklas };
1796c88b1d6cSniklas 
1797c074d1c9Sdrahn static const struct elf_reloc_map mips_reloc_map[] =
1798c88b1d6cSniklas {
1799c074d1c9Sdrahn   { BFD_RELOC_NONE, R_MIPS_NONE },
1800c88b1d6cSniklas   { BFD_RELOC_16, R_MIPS_16 },
1801c88b1d6cSniklas   { BFD_RELOC_32, R_MIPS_32 },
1802c074d1c9Sdrahn   /* There is no BFD reloc for R_MIPS_REL32.  */
1803c88b1d6cSniklas   { BFD_RELOC_64, R_MIPS_64 },
1804c88b1d6cSniklas   { BFD_RELOC_CTOR, R_MIPS_64 },
1805c074d1c9Sdrahn   { BFD_RELOC_16_PCREL, R_MIPS_PC16 },
1806c88b1d6cSniklas   { BFD_RELOC_HI16_S, R_MIPS_HI16 },
1807c88b1d6cSniklas   { BFD_RELOC_LO16, R_MIPS_LO16 },
1808c074d1c9Sdrahn   { BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
1809c074d1c9Sdrahn   { BFD_RELOC_GPREL32, R_MIPS_GPREL32 },
1810c074d1c9Sdrahn   { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
1811c88b1d6cSniklas   { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
1812c88b1d6cSniklas   { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
1813c88b1d6cSniklas   { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
1814c074d1c9Sdrahn   { BFD_RELOC_MIPS_SHIFT5, R_MIPS_SHIFT5 },
1815c074d1c9Sdrahn   { BFD_RELOC_MIPS_SHIFT6, R_MIPS_SHIFT6 },
1816c074d1c9Sdrahn   { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP },
1817b305b0f1Sespie   { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE },
1818b305b0f1Sespie   { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST },
1819c074d1c9Sdrahn   { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
1820c074d1c9Sdrahn   { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
1821c074d1c9Sdrahn   { BFD_RELOC_MIPS_SUB, R_MIPS_SUB },
1822c074d1c9Sdrahn   { BFD_RELOC_MIPS_INSERT_A, R_MIPS_INSERT_A },
1823c074d1c9Sdrahn   { BFD_RELOC_MIPS_INSERT_B, R_MIPS_INSERT_B },
1824c074d1c9Sdrahn   { BFD_RELOC_MIPS_DELETE, R_MIPS_DELETE },
1825c074d1c9Sdrahn   { BFD_RELOC_MIPS_HIGHEST, R_MIPS_HIGHEST },
1826c074d1c9Sdrahn   { BFD_RELOC_MIPS_HIGHER, R_MIPS_HIGHER },
1827c074d1c9Sdrahn   { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
1828c074d1c9Sdrahn   { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 },
1829c074d1c9Sdrahn   { BFD_RELOC_MIPS_SCN_DISP, R_MIPS_SCN_DISP },
1830c074d1c9Sdrahn   { BFD_RELOC_MIPS_REL16, R_MIPS_REL16 },
1831c074d1c9Sdrahn   /* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated.  */
1832c074d1c9Sdrahn   { BFD_RELOC_MIPS_RELGOT, R_MIPS_RELGOT },
1833c074d1c9Sdrahn   { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }
1834c88b1d6cSniklas };
1835c88b1d6cSniklas 
1836c88b1d6cSniklas /* Given a BFD reloc type, return a howto structure.  */
1837c88b1d6cSniklas 
1838c88b1d6cSniklas static reloc_howto_type *
bfd_elf64_bfd_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)1839*007c2a45Smiod bfd_elf64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1840*007c2a45Smiod 				 bfd_reloc_code_real_type code)
1841c88b1d6cSniklas {
1842c88b1d6cSniklas   unsigned int i;
1843c074d1c9Sdrahn   /* FIXME: We default to RELA here instead of choosing the right
1844c074d1c9Sdrahn      relocation variant.  */
1845c074d1c9Sdrahn   reloc_howto_type *howto_table = mips_elf64_howto_table_rela;
1846c88b1d6cSniklas 
1847c074d1c9Sdrahn   for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
1848c074d1c9Sdrahn        i++)
1849c88b1d6cSniklas     {
1850c074d1c9Sdrahn       if (mips_reloc_map[i].bfd_val == code)
1851c074d1c9Sdrahn 	return &howto_table[(int) mips_reloc_map[i].elf_val];
1852c88b1d6cSniklas     }
1853c88b1d6cSniklas 
1854c074d1c9Sdrahn   switch (code)
1855c074d1c9Sdrahn     {
1856c074d1c9Sdrahn     case BFD_RELOC_MIPS16_JMP:
1857c074d1c9Sdrahn       return &elf_mips16_jump_howto;
1858c074d1c9Sdrahn     case BFD_RELOC_MIPS16_GPREL:
1859c074d1c9Sdrahn       return &elf_mips16_gprel_howto;
1860c074d1c9Sdrahn     case BFD_RELOC_VTABLE_INHERIT:
1861c074d1c9Sdrahn       return &elf_mips_gnu_vtinherit_howto;
1862c074d1c9Sdrahn     case BFD_RELOC_VTABLE_ENTRY:
1863c074d1c9Sdrahn       return &elf_mips_gnu_vtentry_howto;
1864*007c2a45Smiod     case BFD_RELOC_16_PCREL_S2:
1865*007c2a45Smiod       return &elf_mips_gnu_rela16_s2;
1866c074d1c9Sdrahn     default:
1867c074d1c9Sdrahn       bfd_set_error (bfd_error_bad_value);
1868c88b1d6cSniklas       return NULL;
1869c88b1d6cSniklas     }
1870c074d1c9Sdrahn }
1871c074d1c9Sdrahn 
1872c074d1c9Sdrahn /* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
1873c074d1c9Sdrahn 
1874c074d1c9Sdrahn static reloc_howto_type *
mips_elf64_rtype_to_howto(unsigned int r_type,bfd_boolean rela_p)1875*007c2a45Smiod mips_elf64_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p)
1876c074d1c9Sdrahn {
1877c074d1c9Sdrahn   switch (r_type)
1878c074d1c9Sdrahn     {
1879c074d1c9Sdrahn     case R_MIPS16_26:
1880c074d1c9Sdrahn       return &elf_mips16_jump_howto;
1881c074d1c9Sdrahn     case R_MIPS16_GPREL:
1882c074d1c9Sdrahn       return &elf_mips16_gprel_howto;
1883c074d1c9Sdrahn     case R_MIPS_GNU_VTINHERIT:
1884c074d1c9Sdrahn       return &elf_mips_gnu_vtinherit_howto;
1885c074d1c9Sdrahn     case R_MIPS_GNU_VTENTRY:
1886c074d1c9Sdrahn       return &elf_mips_gnu_vtentry_howto;
1887*007c2a45Smiod     case R_MIPS_GNU_REL16_S2:
1888*007c2a45Smiod       if (rela_p)
1889*007c2a45Smiod 	return &elf_mips_gnu_rela16_s2;
1890*007c2a45Smiod       else
1891*007c2a45Smiod 	return &elf_mips_gnu_rel16_s2;
1892c074d1c9Sdrahn     default:
1893c074d1c9Sdrahn       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
1894c074d1c9Sdrahn       if (rela_p)
1895c074d1c9Sdrahn 	return &mips_elf64_howto_table_rela[r_type];
1896c074d1c9Sdrahn       else
1897c074d1c9Sdrahn 	return &mips_elf64_howto_table_rel[r_type];
1898c074d1c9Sdrahn       break;
1899c074d1c9Sdrahn     }
1900c074d1c9Sdrahn }
1901c074d1c9Sdrahn 
1902c074d1c9Sdrahn /* Prevent relocation handling by bfd for MIPS ELF64.  */
1903c074d1c9Sdrahn 
1904c074d1c9Sdrahn static void
mips_elf64_info_to_howto_rel(bfd * abfd ATTRIBUTE_UNUSED,arelent * cache_ptr ATTRIBUTE_UNUSED,Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)1905*007c2a45Smiod mips_elf64_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
1906*007c2a45Smiod 			      arelent *cache_ptr ATTRIBUTE_UNUSED,
1907*007c2a45Smiod 			      Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
1908c074d1c9Sdrahn {
1909c074d1c9Sdrahn   BFD_ASSERT (0);
1910c074d1c9Sdrahn }
1911c074d1c9Sdrahn 
1912c074d1c9Sdrahn static void
mips_elf64_info_to_howto_rela(bfd * abfd ATTRIBUTE_UNUSED,arelent * cache_ptr ATTRIBUTE_UNUSED,Elf_Internal_Rela * dst ATTRIBUTE_UNUSED)1913*007c2a45Smiod mips_elf64_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
1914*007c2a45Smiod 			       arelent *cache_ptr ATTRIBUTE_UNUSED,
1915*007c2a45Smiod 			       Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
1916c074d1c9Sdrahn {
1917c074d1c9Sdrahn   BFD_ASSERT (0);
1918c074d1c9Sdrahn }
1919c88b1d6cSniklas 
1920c88b1d6cSniklas /* Since each entry in an SHT_REL or SHT_RELA section can represent up
1921c88b1d6cSniklas    to three relocs, we must tell the user to allocate more space.  */
1922c88b1d6cSniklas 
1923c88b1d6cSniklas static long
mips_elf64_get_reloc_upper_bound(bfd * abfd ATTRIBUTE_UNUSED,asection * sec)1924*007c2a45Smiod mips_elf64_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
1925c88b1d6cSniklas {
1926c88b1d6cSniklas   return (sec->reloc_count * 3 + 1) * sizeof (arelent *);
1927c88b1d6cSniklas }
1928c88b1d6cSniklas 
1929c074d1c9Sdrahn static long
mips_elf64_get_dynamic_reloc_upper_bound(bfd * abfd)1930*007c2a45Smiod mips_elf64_get_dynamic_reloc_upper_bound (bfd *abfd)
1931c074d1c9Sdrahn {
1932c074d1c9Sdrahn   return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3;
1933c074d1c9Sdrahn }
1934c88b1d6cSniklas 
1935c074d1c9Sdrahn /* We must also copy more relocations than the corresponding functions
1936c074d1c9Sdrahn    in elf.c would, so the two following functions are slightly
1937c074d1c9Sdrahn    modified from elf.c, that multiply the external relocation count by
1938c074d1c9Sdrahn    3 to obtain the internal relocation count.  */
1939c074d1c9Sdrahn 
1940c074d1c9Sdrahn static long
mips_elf64_canonicalize_reloc(bfd * abfd,sec_ptr section,arelent ** relptr,asymbol ** symbols)1941*007c2a45Smiod mips_elf64_canonicalize_reloc (bfd *abfd, sec_ptr section,
1942*007c2a45Smiod 			       arelent **relptr, asymbol **symbols)
1943c074d1c9Sdrahn {
1944c074d1c9Sdrahn   arelent *tblptr;
1945c074d1c9Sdrahn   unsigned int i;
1946*007c2a45Smiod   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
1947c074d1c9Sdrahn 
1948c074d1c9Sdrahn   if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE))
1949c074d1c9Sdrahn     return -1;
1950c074d1c9Sdrahn 
1951c074d1c9Sdrahn   tblptr = section->relocation;
1952c074d1c9Sdrahn   for (i = 0; i < section->reloc_count * 3; i++)
1953c074d1c9Sdrahn     *relptr++ = tblptr++;
1954c074d1c9Sdrahn 
1955c074d1c9Sdrahn   *relptr = NULL;
1956c074d1c9Sdrahn 
1957c074d1c9Sdrahn   return section->reloc_count * 3;
1958c074d1c9Sdrahn }
1959c074d1c9Sdrahn 
1960c074d1c9Sdrahn static long
mips_elf64_canonicalize_dynamic_reloc(bfd * abfd,arelent ** storage,asymbol ** syms)1961*007c2a45Smiod mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
1962*007c2a45Smiod 				       asymbol **syms)
1963c074d1c9Sdrahn {
1964*007c2a45Smiod   bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
1965c074d1c9Sdrahn   asection *s;
1966c074d1c9Sdrahn   long ret;
1967c074d1c9Sdrahn 
1968c074d1c9Sdrahn   if (elf_dynsymtab (abfd) == 0)
1969c074d1c9Sdrahn     {
1970c074d1c9Sdrahn       bfd_set_error (bfd_error_invalid_operation);
1971c074d1c9Sdrahn       return -1;
1972c074d1c9Sdrahn     }
1973c074d1c9Sdrahn 
1974c074d1c9Sdrahn   slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
1975c074d1c9Sdrahn   ret = 0;
1976c074d1c9Sdrahn   for (s = abfd->sections; s != NULL; s = s->next)
1977c074d1c9Sdrahn     {
1978c074d1c9Sdrahn       if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
1979c074d1c9Sdrahn 	  && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
1980c074d1c9Sdrahn 	      || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
1981c074d1c9Sdrahn 	{
1982c074d1c9Sdrahn 	  arelent *p;
1983c074d1c9Sdrahn 	  long count, i;
1984c074d1c9Sdrahn 
1985c074d1c9Sdrahn 	  if (! (*slurp_relocs) (abfd, s, syms, TRUE))
1986c074d1c9Sdrahn 	    return -1;
1987c074d1c9Sdrahn 	  count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize * 3;
1988c074d1c9Sdrahn 	  p = s->relocation;
1989c074d1c9Sdrahn 	  for (i = 0; i < count; i++)
1990c074d1c9Sdrahn 	    *storage++ = p++;
1991c074d1c9Sdrahn 	  ret += count;
1992c074d1c9Sdrahn 	}
1993c074d1c9Sdrahn     }
1994c074d1c9Sdrahn 
1995c074d1c9Sdrahn   *storage = NULL;
1996c074d1c9Sdrahn 
1997c074d1c9Sdrahn   return ret;
1998c074d1c9Sdrahn }
1999c074d1c9Sdrahn 
2000c074d1c9Sdrahn /* Read the relocations from one reloc section.  This is mostly copied
2001c074d1c9Sdrahn    from elfcode.h, except for the changes to expand one external
2002c074d1c9Sdrahn    relocation to 3 internal ones.  We must unfortunately set
2003c074d1c9Sdrahn    reloc_count to the number of external relocations, because a lot of
2004c074d1c9Sdrahn    generic code seems to depend on this.  */
2005c074d1c9Sdrahn 
2006c074d1c9Sdrahn static bfd_boolean
mips_elf64_slurp_one_reloc_table(bfd * abfd,asection * asect,Elf_Internal_Shdr * rel_hdr,bfd_size_type reloc_count,arelent * relents,asymbol ** symbols,bfd_boolean dynamic)2007*007c2a45Smiod mips_elf64_slurp_one_reloc_table (bfd *abfd, asection *asect,
2008*007c2a45Smiod 				  Elf_Internal_Shdr *rel_hdr,
2009*007c2a45Smiod 				  bfd_size_type reloc_count,
2010*007c2a45Smiod 				  arelent *relents, asymbol **symbols,
2011*007c2a45Smiod 				  bfd_boolean dynamic)
2012c88b1d6cSniklas {
2013*007c2a45Smiod   void *allocated;
2014c88b1d6cSniklas   bfd_byte *native_relocs;
2015c88b1d6cSniklas   arelent *relent;
2016c074d1c9Sdrahn   bfd_vma i;
2017c88b1d6cSniklas   int entsize;
2018*007c2a45Smiod   bfd_boolean rela_p;
2019c88b1d6cSniklas 
2020*007c2a45Smiod   allocated = bfd_malloc (rel_hdr->sh_size);
2021c88b1d6cSniklas   if (allocated == NULL)
2022c074d1c9Sdrahn     return FALSE;
2023c88b1d6cSniklas 
2024c88b1d6cSniklas   if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
2025c074d1c9Sdrahn       || (bfd_bread (allocated, rel_hdr->sh_size, abfd)
2026c074d1c9Sdrahn 	  != rel_hdr->sh_size))
2027c88b1d6cSniklas     goto error_return;
2028c88b1d6cSniklas 
2029*007c2a45Smiod   native_relocs = allocated;
2030c88b1d6cSniklas 
2031c88b1d6cSniklas   entsize = rel_hdr->sh_entsize;
2032c88b1d6cSniklas   BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel)
2033c88b1d6cSniklas 	      || entsize == sizeof (Elf64_Mips_External_Rela));
2034c88b1d6cSniklas 
2035c88b1d6cSniklas   if (entsize == sizeof (Elf64_Mips_External_Rel))
2036*007c2a45Smiod     rela_p = FALSE;
2037c88b1d6cSniklas   else
2038*007c2a45Smiod     rela_p = TRUE;
2039c88b1d6cSniklas 
2040c074d1c9Sdrahn   for (i = 0, relent = relents;
2041c074d1c9Sdrahn        i < reloc_count;
2042c074d1c9Sdrahn        i++, native_relocs += entsize)
2043c88b1d6cSniklas     {
2044c88b1d6cSniklas       Elf64_Mips_Internal_Rela rela;
2045c074d1c9Sdrahn       bfd_boolean used_sym, used_ssym;
2046c88b1d6cSniklas       int ir;
2047c88b1d6cSniklas 
2048c88b1d6cSniklas       if (entsize == sizeof (Elf64_Mips_External_Rela))
2049c88b1d6cSniklas 	mips_elf64_swap_reloca_in (abfd,
2050c88b1d6cSniklas 				   (Elf64_Mips_External_Rela *) native_relocs,
2051c88b1d6cSniklas 				   &rela);
2052c88b1d6cSniklas       else
2053c88b1d6cSniklas 	mips_elf64_swap_reloc_in (abfd,
2054c88b1d6cSniklas 				  (Elf64_Mips_External_Rel *) native_relocs,
2055c074d1c9Sdrahn 				  &rela);
2056c88b1d6cSniklas 
2057c074d1c9Sdrahn       /* Each entry represents exactly three actual relocations.  */
2058c88b1d6cSniklas 
2059c074d1c9Sdrahn       used_sym = FALSE;
2060c074d1c9Sdrahn       used_ssym = FALSE;
2061c88b1d6cSniklas       for (ir = 0; ir < 3; ir++)
2062c88b1d6cSniklas 	{
2063b305b0f1Sespie 	  enum elf_mips_reloc_type type;
2064c88b1d6cSniklas 
2065c88b1d6cSniklas 	  switch (ir)
2066c88b1d6cSniklas 	    {
2067c88b1d6cSniklas 	    default:
2068c88b1d6cSniklas 	      abort ();
2069c88b1d6cSniklas 	    case 0:
2070b305b0f1Sespie 	      type = (enum elf_mips_reloc_type) rela.r_type;
2071c88b1d6cSniklas 	      break;
2072c88b1d6cSniklas 	    case 1:
2073b305b0f1Sespie 	      type = (enum elf_mips_reloc_type) rela.r_type2;
2074c88b1d6cSniklas 	      break;
2075c88b1d6cSniklas 	    case 2:
2076b305b0f1Sespie 	      type = (enum elf_mips_reloc_type) rela.r_type3;
2077c88b1d6cSniklas 	      break;
2078c88b1d6cSniklas 	    }
2079c88b1d6cSniklas 
2080c88b1d6cSniklas 	  /* Some types require symbols, whereas some do not.  */
2081c88b1d6cSniklas 	  switch (type)
2082c88b1d6cSniklas 	    {
2083c88b1d6cSniklas 	    case R_MIPS_NONE:
2084c88b1d6cSniklas 	    case R_MIPS_LITERAL:
2085c88b1d6cSniklas 	    case R_MIPS_INSERT_A:
2086c88b1d6cSniklas 	    case R_MIPS_INSERT_B:
2087c88b1d6cSniklas 	    case R_MIPS_DELETE:
2088c88b1d6cSniklas 	      relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
2089c88b1d6cSniklas 	      break;
2090c88b1d6cSniklas 
2091c88b1d6cSniklas 	    default:
2092c88b1d6cSniklas 	      if (! used_sym)
2093c88b1d6cSniklas 		{
2094c88b1d6cSniklas 		  if (rela.r_sym == 0)
2095c88b1d6cSniklas 		    relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
2096c88b1d6cSniklas 		  else
2097c88b1d6cSniklas 		    {
2098c88b1d6cSniklas 		      asymbol **ps, *s;
2099c88b1d6cSniklas 
2100c88b1d6cSniklas 		      ps = symbols + rela.r_sym - 1;
2101c88b1d6cSniklas 		      s = *ps;
2102c88b1d6cSniklas 		      if ((s->flags & BSF_SECTION_SYM) == 0)
2103c88b1d6cSniklas 			relent->sym_ptr_ptr = ps;
2104c88b1d6cSniklas 		      else
2105c88b1d6cSniklas 			relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
2106c88b1d6cSniklas 		    }
2107c88b1d6cSniklas 
2108c074d1c9Sdrahn 		  used_sym = TRUE;
2109c88b1d6cSniklas 		}
2110c88b1d6cSniklas 	      else if (! used_ssym)
2111c88b1d6cSniklas 		{
2112c88b1d6cSniklas 		  switch (rela.r_ssym)
2113c88b1d6cSniklas 		    {
2114c88b1d6cSniklas 		    case RSS_UNDEF:
2115c88b1d6cSniklas 		      relent->sym_ptr_ptr =
2116c88b1d6cSniklas 			bfd_abs_section_ptr->symbol_ptr_ptr;
2117c88b1d6cSniklas 		      break;
2118c88b1d6cSniklas 
2119c88b1d6cSniklas 		    case RSS_GP:
2120c88b1d6cSniklas 		    case RSS_GP0:
2121c88b1d6cSniklas 		    case RSS_LOC:
2122c88b1d6cSniklas 		      /* FIXME: I think these need to be handled using
2123c88b1d6cSniklas                          special howto structures.  */
2124c88b1d6cSniklas 		      BFD_ASSERT (0);
2125c88b1d6cSniklas 		      break;
2126c88b1d6cSniklas 
2127c88b1d6cSniklas 		    default:
2128c88b1d6cSniklas 		      BFD_ASSERT (0);
2129c88b1d6cSniklas 		      break;
2130c88b1d6cSniklas 		    }
2131c88b1d6cSniklas 
2132c074d1c9Sdrahn 		  used_ssym = TRUE;
2133c88b1d6cSniklas 		}
2134c88b1d6cSniklas 	      else
2135c88b1d6cSniklas 		relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
2136c88b1d6cSniklas 
2137c88b1d6cSniklas 	      break;
2138c88b1d6cSniklas 	    }
2139c88b1d6cSniklas 
2140c88b1d6cSniklas 	  /* The address of an ELF reloc is section relative for an
2141c88b1d6cSniklas 	     object file, and absolute for an executable file or
2142c88b1d6cSniklas 	     shared library.  The address of a BFD reloc is always
2143c88b1d6cSniklas 	     section relative.  */
2144c074d1c9Sdrahn 	  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
2145c88b1d6cSniklas 	    relent->address = rela.r_offset;
2146c88b1d6cSniklas 	  else
2147c88b1d6cSniklas 	    relent->address = rela.r_offset - asect->vma;
2148c88b1d6cSniklas 
2149c88b1d6cSniklas 	  relent->addend = rela.r_addend;
2150c88b1d6cSniklas 
2151*007c2a45Smiod 	  relent->howto = mips_elf64_rtype_to_howto (type, rela_p);
2152c88b1d6cSniklas 
2153c88b1d6cSniklas 	  ++relent;
2154c88b1d6cSniklas 	}
2155c88b1d6cSniklas     }
2156c88b1d6cSniklas 
2157c074d1c9Sdrahn   asect->reloc_count += (relent - relents) / 3;
2158c88b1d6cSniklas 
2159c88b1d6cSniklas   if (allocated != NULL)
2160c88b1d6cSniklas     free (allocated);
2161c88b1d6cSniklas 
2162c074d1c9Sdrahn   return TRUE;
2163c88b1d6cSniklas 
2164c88b1d6cSniklas  error_return:
2165c88b1d6cSniklas   if (allocated != NULL)
2166c88b1d6cSniklas     free (allocated);
2167c074d1c9Sdrahn   return FALSE;
2168c88b1d6cSniklas }
2169c88b1d6cSniklas 
2170c88b1d6cSniklas /* Read the relocations.  On Irix 6, there can be two reloc sections
2171c074d1c9Sdrahn    associated with a single data section.  This is copied from
2172c074d1c9Sdrahn    elfcode.h as well, with changes as small as accounting for 3
2173c074d1c9Sdrahn    internal relocs per external reloc and resetting reloc_count to
2174c074d1c9Sdrahn    zero before processing the relocs of a section.  */
2175c88b1d6cSniklas 
2176c074d1c9Sdrahn static bfd_boolean
mips_elf64_slurp_reloc_table(bfd * abfd,asection * asect,asymbol ** symbols,bfd_boolean dynamic)2177*007c2a45Smiod mips_elf64_slurp_reloc_table (bfd *abfd, asection *asect,
2178*007c2a45Smiod 			      asymbol **symbols, bfd_boolean dynamic)
2179c88b1d6cSniklas {
2180c88b1d6cSniklas   struct bfd_elf_section_data * const d = elf_section_data (asect);
2181c074d1c9Sdrahn   Elf_Internal_Shdr *rel_hdr;
2182c074d1c9Sdrahn   Elf_Internal_Shdr *rel_hdr2;
2183c074d1c9Sdrahn   bfd_size_type reloc_count;
2184c074d1c9Sdrahn   bfd_size_type reloc_count2;
2185c074d1c9Sdrahn   arelent *relents;
2186c074d1c9Sdrahn   bfd_size_type amt;
2187c88b1d6cSniklas 
2188c074d1c9Sdrahn   if (asect->relocation != NULL)
2189c074d1c9Sdrahn     return TRUE;
2190c074d1c9Sdrahn 
2191c074d1c9Sdrahn   if (! dynamic)
21926a4c786fSespie     {
2193c074d1c9Sdrahn       if ((asect->flags & SEC_RELOC) == 0
2194c074d1c9Sdrahn 	  || asect->reloc_count == 0)
2195c074d1c9Sdrahn 	return TRUE;
2196c074d1c9Sdrahn 
2197c074d1c9Sdrahn       rel_hdr = &d->rel_hdr;
2198c074d1c9Sdrahn       reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
2199c074d1c9Sdrahn       rel_hdr2 = d->rel_hdr2;
2200c074d1c9Sdrahn       reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0);
2201c074d1c9Sdrahn 
2202c074d1c9Sdrahn       BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2);
2203c074d1c9Sdrahn       BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
2204c074d1c9Sdrahn 		  || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
2205c074d1c9Sdrahn 
2206c074d1c9Sdrahn     }
2207c074d1c9Sdrahn   else
2208c074d1c9Sdrahn     {
2209c074d1c9Sdrahn       /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
2210c074d1c9Sdrahn 	 case because relocations against this section may use the
2211c074d1c9Sdrahn 	 dynamic symbol table, and in that case bfd_section_from_shdr
2212c074d1c9Sdrahn 	 in elf.c does not update the RELOC_COUNT.  */
2213c074d1c9Sdrahn       if (asect->_raw_size == 0)
2214c074d1c9Sdrahn 	return TRUE;
2215c074d1c9Sdrahn 
2216c074d1c9Sdrahn       rel_hdr = &d->this_hdr;
2217c074d1c9Sdrahn       reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
2218c074d1c9Sdrahn       rel_hdr2 = NULL;
2219c074d1c9Sdrahn       reloc_count2 = 0;
22206a4c786fSespie     }
22216a4c786fSespie 
2222c88b1d6cSniklas   /* Allocate space for 3 arelent structures for each Rel structure.  */
2223c074d1c9Sdrahn   amt = (reloc_count + reloc_count2) * 3 * sizeof (arelent);
2224*007c2a45Smiod   relents = bfd_alloc (abfd, amt);
2225c074d1c9Sdrahn   if (relents == NULL)
2226c074d1c9Sdrahn     return FALSE;
2227c88b1d6cSniklas 
2228c88b1d6cSniklas   /* The slurp_one_reloc_table routine increments reloc_count.  */
2229c88b1d6cSniklas   asect->reloc_count = 0;
2230c88b1d6cSniklas 
2231c074d1c9Sdrahn   if (! mips_elf64_slurp_one_reloc_table (abfd, asect,
2232c074d1c9Sdrahn 					  rel_hdr, reloc_count,
2233c074d1c9Sdrahn 					  relents,
2234c074d1c9Sdrahn 					  symbols, dynamic))
2235c074d1c9Sdrahn     return FALSE;
2236c88b1d6cSniklas   if (d->rel_hdr2 != NULL)
2237c88b1d6cSniklas     {
2238c074d1c9Sdrahn       if (! mips_elf64_slurp_one_reloc_table (abfd, asect,
2239c074d1c9Sdrahn 					      rel_hdr2, reloc_count2,
2240c074d1c9Sdrahn 					      relents + reloc_count * 3,
2241c074d1c9Sdrahn 					      symbols, dynamic))
2242c074d1c9Sdrahn 	return FALSE;
2243c88b1d6cSniklas     }
2244c88b1d6cSniklas 
2245c074d1c9Sdrahn   asect->relocation = relents;
2246c074d1c9Sdrahn   return TRUE;
2247c88b1d6cSniklas }
2248c88b1d6cSniklas 
2249c88b1d6cSniklas /* Write out the relocations.  */
2250c88b1d6cSniklas 
2251c88b1d6cSniklas static void
mips_elf64_write_relocs(bfd * abfd,asection * sec,void * data)2252*007c2a45Smiod mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data)
2253c88b1d6cSniklas {
2254*007c2a45Smiod   bfd_boolean *failedp = data;
2255c074d1c9Sdrahn   int count;
2256c074d1c9Sdrahn   Elf_Internal_Shdr *rel_hdr;
2257c88b1d6cSniklas   unsigned int idx;
2258c88b1d6cSniklas 
2259c88b1d6cSniklas   /* If we have already failed, don't do anything.  */
2260c88b1d6cSniklas   if (*failedp)
2261c88b1d6cSniklas     return;
2262c88b1d6cSniklas 
2263c88b1d6cSniklas   if ((sec->flags & SEC_RELOC) == 0)
2264c88b1d6cSniklas     return;
2265c88b1d6cSniklas 
2266c88b1d6cSniklas   /* The linker backend writes the relocs out itself, and sets the
2267c88b1d6cSniklas      reloc_count field to zero to inhibit writing them here.  Also,
2268c88b1d6cSniklas      sometimes the SEC_RELOC flag gets set even when there aren't any
2269c88b1d6cSniklas      relocs.  */
2270c88b1d6cSniklas   if (sec->reloc_count == 0)
2271c88b1d6cSniklas     return;
2272c88b1d6cSniklas 
2273c88b1d6cSniklas   /* We can combine up to three relocs that refer to the same address
2274c88b1d6cSniklas      if the latter relocs have no associated symbol.  */
2275c88b1d6cSniklas   count = 0;
2276c88b1d6cSniklas   for (idx = 0; idx < sec->reloc_count; idx++)
2277c88b1d6cSniklas     {
2278c88b1d6cSniklas       bfd_vma addr;
2279c88b1d6cSniklas       unsigned int i;
2280c88b1d6cSniklas 
2281c88b1d6cSniklas       ++count;
2282c88b1d6cSniklas 
2283c88b1d6cSniklas       addr = sec->orelocation[idx]->address;
2284c88b1d6cSniklas       for (i = 0; i < 2; i++)
2285c88b1d6cSniklas 	{
2286c88b1d6cSniklas 	  arelent *r;
2287c88b1d6cSniklas 
2288c88b1d6cSniklas 	  if (idx + 1 >= sec->reloc_count)
2289c88b1d6cSniklas 	    break;
2290c88b1d6cSniklas 	  r = sec->orelocation[idx + 1];
2291c88b1d6cSniklas 	  if (r->address != addr
2292c88b1d6cSniklas 	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
2293c88b1d6cSniklas 	      || (*r->sym_ptr_ptr)->value != 0)
2294c88b1d6cSniklas 	    break;
2295c88b1d6cSniklas 
2296c88b1d6cSniklas 	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
2297c88b1d6cSniklas 
2298c88b1d6cSniklas 	  ++idx;
2299c88b1d6cSniklas 	}
2300c88b1d6cSniklas     }
2301c88b1d6cSniklas 
2302c074d1c9Sdrahn   rel_hdr = &elf_section_data (sec)->rel_hdr;
2303c88b1d6cSniklas 
2304c074d1c9Sdrahn   /* Do the actual relocation.  */
2305c074d1c9Sdrahn 
2306c074d1c9Sdrahn   if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rel))
2307c074d1c9Sdrahn     mips_elf64_write_rel (abfd, sec, rel_hdr, &count, data);
2308c074d1c9Sdrahn   else if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rela))
2309c074d1c9Sdrahn     mips_elf64_write_rela (abfd, sec, rel_hdr, &count, data);
2310c074d1c9Sdrahn   else
2311c074d1c9Sdrahn     BFD_ASSERT (0);
2312c074d1c9Sdrahn }
2313c074d1c9Sdrahn 
2314c074d1c9Sdrahn static void
mips_elf64_write_rel(bfd * abfd,asection * sec,Elf_Internal_Shdr * rel_hdr,int * count,void * data)2315*007c2a45Smiod mips_elf64_write_rel (bfd *abfd, asection *sec,
2316*007c2a45Smiod 		      Elf_Internal_Shdr *rel_hdr,
2317*007c2a45Smiod 		      int *count, void *data)
2318c074d1c9Sdrahn {
2319*007c2a45Smiod   bfd_boolean *failedp = data;
2320c074d1c9Sdrahn   Elf64_Mips_External_Rel *ext_rel;
2321c074d1c9Sdrahn   unsigned int idx;
2322c074d1c9Sdrahn   asymbol *last_sym = 0;
2323c074d1c9Sdrahn   int last_sym_idx = 0;
2324c074d1c9Sdrahn 
2325*007c2a45Smiod   rel_hdr->sh_size = rel_hdr->sh_entsize * *count;
2326*007c2a45Smiod   rel_hdr->contents = bfd_alloc (abfd, rel_hdr->sh_size);
2327c074d1c9Sdrahn   if (rel_hdr->contents == NULL)
2328c074d1c9Sdrahn     {
2329c074d1c9Sdrahn       *failedp = TRUE;
2330c074d1c9Sdrahn       return;
2331c074d1c9Sdrahn     }
2332c074d1c9Sdrahn 
2333c074d1c9Sdrahn   ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents;
2334c074d1c9Sdrahn   for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++)
2335c074d1c9Sdrahn     {
2336c074d1c9Sdrahn       arelent *ptr;
2337c074d1c9Sdrahn       Elf64_Mips_Internal_Rela int_rel;
2338c074d1c9Sdrahn       asymbol *sym;
2339c074d1c9Sdrahn       int n;
2340c074d1c9Sdrahn       unsigned int i;
2341c074d1c9Sdrahn 
2342c074d1c9Sdrahn       ptr = sec->orelocation[idx];
2343c074d1c9Sdrahn 
2344c074d1c9Sdrahn       /* The address of an ELF reloc is section relative for an object
2345c074d1c9Sdrahn 	 file, and absolute for an executable file or shared library.
2346c074d1c9Sdrahn 	 The address of a BFD reloc is always section relative.  */
2347c074d1c9Sdrahn       if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
2348c074d1c9Sdrahn 	int_rel.r_offset = ptr->address;
2349c074d1c9Sdrahn       else
2350c074d1c9Sdrahn 	int_rel.r_offset = ptr->address + sec->vma;
2351c074d1c9Sdrahn 
2352c074d1c9Sdrahn       sym = *ptr->sym_ptr_ptr;
2353c074d1c9Sdrahn       if (sym == last_sym)
2354c074d1c9Sdrahn 	n = last_sym_idx;
2355c074d1c9Sdrahn       else
2356c074d1c9Sdrahn 	{
2357c074d1c9Sdrahn 	  last_sym = sym;
2358c074d1c9Sdrahn 	  n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
2359c074d1c9Sdrahn 	  if (n < 0)
2360c074d1c9Sdrahn 	    {
2361c074d1c9Sdrahn 	      *failedp = TRUE;
2362c074d1c9Sdrahn 	      return;
2363c074d1c9Sdrahn 	    }
2364c074d1c9Sdrahn 	  last_sym_idx = n;
2365c074d1c9Sdrahn 	}
2366c074d1c9Sdrahn 
2367c074d1c9Sdrahn       int_rel.r_sym = n;
2368c074d1c9Sdrahn       int_rel.r_ssym = RSS_UNDEF;
2369c074d1c9Sdrahn 
2370c074d1c9Sdrahn       if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
2371c074d1c9Sdrahn 	  && ! _bfd_elf_validate_reloc (abfd, ptr))
2372c074d1c9Sdrahn 	{
2373c074d1c9Sdrahn 	  *failedp = TRUE;
2374c074d1c9Sdrahn 	  return;
2375c074d1c9Sdrahn 	}
2376c074d1c9Sdrahn 
2377c074d1c9Sdrahn       int_rel.r_type = ptr->howto->type;
2378c074d1c9Sdrahn       int_rel.r_type2 = (int) R_MIPS_NONE;
2379c074d1c9Sdrahn       int_rel.r_type3 = (int) R_MIPS_NONE;
2380c074d1c9Sdrahn 
2381c074d1c9Sdrahn       for (i = 0; i < 2; i++)
2382c074d1c9Sdrahn 	{
2383c074d1c9Sdrahn 	  arelent *r;
2384c074d1c9Sdrahn 
2385c074d1c9Sdrahn 	  if (idx + 1 >= sec->reloc_count)
2386c074d1c9Sdrahn 	    break;
2387c074d1c9Sdrahn 	  r = sec->orelocation[idx + 1];
2388c074d1c9Sdrahn 	  if (r->address != ptr->address
2389c074d1c9Sdrahn 	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
2390c074d1c9Sdrahn 	      || (*r->sym_ptr_ptr)->value != 0)
2391c074d1c9Sdrahn 	    break;
2392c074d1c9Sdrahn 
2393c074d1c9Sdrahn 	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
2394c074d1c9Sdrahn 
2395c074d1c9Sdrahn 	  if (i == 0)
2396c074d1c9Sdrahn 	    int_rel.r_type2 = r->howto->type;
2397c074d1c9Sdrahn 	  else
2398c074d1c9Sdrahn 	    int_rel.r_type3 = r->howto->type;
2399c074d1c9Sdrahn 
2400c074d1c9Sdrahn 	  ++idx;
2401c074d1c9Sdrahn 	}
2402c074d1c9Sdrahn 
2403c074d1c9Sdrahn       mips_elf64_swap_reloc_out (abfd, &int_rel, ext_rel);
2404c074d1c9Sdrahn     }
2405c074d1c9Sdrahn 
2406c074d1c9Sdrahn   BFD_ASSERT (ext_rel - (Elf64_Mips_External_Rel *) rel_hdr->contents
2407c074d1c9Sdrahn 	      == *count);
2408c074d1c9Sdrahn }
2409c074d1c9Sdrahn 
2410c074d1c9Sdrahn static void
mips_elf64_write_rela(bfd * abfd,asection * sec,Elf_Internal_Shdr * rela_hdr,int * count,void * data)2411*007c2a45Smiod mips_elf64_write_rela (bfd *abfd, asection *sec,
2412*007c2a45Smiod 		       Elf_Internal_Shdr *rela_hdr,
2413*007c2a45Smiod 		       int *count, void *data)
2414c074d1c9Sdrahn {
2415*007c2a45Smiod   bfd_boolean *failedp = data;
2416c074d1c9Sdrahn   Elf64_Mips_External_Rela *ext_rela;
2417c074d1c9Sdrahn   unsigned int idx;
2418c074d1c9Sdrahn   asymbol *last_sym = 0;
2419c074d1c9Sdrahn   int last_sym_idx = 0;
2420c074d1c9Sdrahn 
2421*007c2a45Smiod   rela_hdr->sh_size = rela_hdr->sh_entsize * *count;
2422*007c2a45Smiod   rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size);
2423c88b1d6cSniklas   if (rela_hdr->contents == NULL)
2424c88b1d6cSniklas     {
2425c074d1c9Sdrahn       *failedp = TRUE;
2426c88b1d6cSniklas       return;
2427c88b1d6cSniklas     }
2428c88b1d6cSniklas 
2429c88b1d6cSniklas   ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents;
2430c88b1d6cSniklas   for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++)
2431c88b1d6cSniklas     {
2432c88b1d6cSniklas       arelent *ptr;
2433c88b1d6cSniklas       Elf64_Mips_Internal_Rela int_rela;
2434c88b1d6cSniklas       asymbol *sym;
2435c88b1d6cSniklas       int n;
2436c88b1d6cSniklas       unsigned int i;
2437c88b1d6cSniklas 
2438c88b1d6cSniklas       ptr = sec->orelocation[idx];
2439c88b1d6cSniklas 
2440c88b1d6cSniklas       /* The address of an ELF reloc is section relative for an object
2441c88b1d6cSniklas 	 file, and absolute for an executable file or shared library.
2442c88b1d6cSniklas 	 The address of a BFD reloc is always section relative.  */
2443c88b1d6cSniklas       if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
2444c88b1d6cSniklas 	int_rela.r_offset = ptr->address;
2445c88b1d6cSniklas       else
2446c88b1d6cSniklas 	int_rela.r_offset = ptr->address + sec->vma;
2447c88b1d6cSniklas 
2448c88b1d6cSniklas       sym = *ptr->sym_ptr_ptr;
2449c88b1d6cSniklas       if (sym == last_sym)
2450c88b1d6cSniklas 	n = last_sym_idx;
2451c88b1d6cSniklas       else
2452c88b1d6cSniklas 	{
2453c88b1d6cSniklas 	  last_sym = sym;
2454c88b1d6cSniklas 	  n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
2455c88b1d6cSniklas 	  if (n < 0)
2456c88b1d6cSniklas 	    {
2457c074d1c9Sdrahn 	      *failedp = TRUE;
2458c88b1d6cSniklas 	      return;
2459c88b1d6cSniklas 	    }
2460c88b1d6cSniklas 	  last_sym_idx = n;
2461c88b1d6cSniklas 	}
2462c88b1d6cSniklas 
2463c88b1d6cSniklas       int_rela.r_sym = n;
2464c88b1d6cSniklas       int_rela.r_addend = ptr->addend;
2465c88b1d6cSniklas       int_rela.r_ssym = RSS_UNDEF;
2466c88b1d6cSniklas 
2467c88b1d6cSniklas       if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
2468c88b1d6cSniklas 	  && ! _bfd_elf_validate_reloc (abfd, ptr))
2469c88b1d6cSniklas 	{
2470c074d1c9Sdrahn 	  *failedp = TRUE;
2471c88b1d6cSniklas 	  return;
2472c88b1d6cSniklas 	}
2473c88b1d6cSniklas 
2474c88b1d6cSniklas       int_rela.r_type = ptr->howto->type;
2475c88b1d6cSniklas       int_rela.r_type2 = (int) R_MIPS_NONE;
2476c88b1d6cSniklas       int_rela.r_type3 = (int) R_MIPS_NONE;
2477c88b1d6cSniklas 
2478c88b1d6cSniklas       for (i = 0; i < 2; i++)
2479c88b1d6cSniklas 	{
2480c88b1d6cSniklas 	  arelent *r;
2481c88b1d6cSniklas 
2482c88b1d6cSniklas 	  if (idx + 1 >= sec->reloc_count)
2483c88b1d6cSniklas 	    break;
2484c88b1d6cSniklas 	  r = sec->orelocation[idx + 1];
2485c88b1d6cSniklas 	  if (r->address != ptr->address
2486c88b1d6cSniklas 	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
2487c88b1d6cSniklas 	      || (*r->sym_ptr_ptr)->value != 0)
2488c88b1d6cSniklas 	    break;
2489c88b1d6cSniklas 
2490c88b1d6cSniklas 	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
2491c88b1d6cSniklas 
2492c88b1d6cSniklas 	  if (i == 0)
2493c88b1d6cSniklas 	    int_rela.r_type2 = r->howto->type;
2494c88b1d6cSniklas 	  else
2495c88b1d6cSniklas 	    int_rela.r_type3 = r->howto->type;
2496c88b1d6cSniklas 
2497c88b1d6cSniklas 	  ++idx;
2498c88b1d6cSniklas 	}
2499c88b1d6cSniklas 
2500c88b1d6cSniklas       mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela);
2501c88b1d6cSniklas     }
2502c88b1d6cSniklas 
2503c88b1d6cSniklas   BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents
2504c074d1c9Sdrahn 	      == *count);
2505c88b1d6cSniklas }
2506c88b1d6cSniklas 
2507c074d1c9Sdrahn /* Set the right machine number for a MIPS ELF file.  */
25084361b62eSniklas 
2509c074d1c9Sdrahn static bfd_boolean
mips_elf64_object_p(bfd * abfd)2510*007c2a45Smiod mips_elf64_object_p (bfd *abfd)
25114361b62eSniklas {
2512c074d1c9Sdrahn   unsigned long mach;
25134361b62eSniklas 
2514c074d1c9Sdrahn   /* Irix 6 is broken.  Object file symbol tables are not always
2515c074d1c9Sdrahn      sorted correctly such that local symbols precede global symbols,
2516c074d1c9Sdrahn      and the sh_info field in the symbol table is not always right.  */
2517c074d1c9Sdrahn   if (elf64_mips_irix_compat (abfd) != ict_none)
2518c074d1c9Sdrahn     elf_bad_symtab (abfd) = TRUE;
25194361b62eSniklas 
2520c074d1c9Sdrahn   mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags);
2521c074d1c9Sdrahn   bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach);
2522c074d1c9Sdrahn   return TRUE;
25234361b62eSniklas }
25244361b62eSniklas 
2525c074d1c9Sdrahn /* Depending on the target vector we generate some version of Irix
2526c074d1c9Sdrahn    executables or "normal" MIPS ELF ABI executables.  */
2527c074d1c9Sdrahn static irix_compat_t
elf64_mips_irix_compat(bfd * abfd)2528*007c2a45Smiod elf64_mips_irix_compat (bfd *abfd)
25294361b62eSniklas {
2530c074d1c9Sdrahn   if ((abfd->xvec == &bfd_elf64_bigmips_vec)
2531c074d1c9Sdrahn       || (abfd->xvec == &bfd_elf64_littlemips_vec))
2532c074d1c9Sdrahn     return ict_irix6;
2533c074d1c9Sdrahn   else
2534c074d1c9Sdrahn     return ict_none;
2535c074d1c9Sdrahn }
2536c074d1c9Sdrahn 
2537c074d1c9Sdrahn /* Support for core dump NOTE sections.  */
2538c074d1c9Sdrahn static bfd_boolean
elf64_mips_grok_prstatus(bfd * abfd,Elf_Internal_Note * note)2539*007c2a45Smiod elf64_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
2540c074d1c9Sdrahn {
2541c074d1c9Sdrahn   int offset;
2542c074d1c9Sdrahn   unsigned int raw_size;
2543c074d1c9Sdrahn 
2544c074d1c9Sdrahn   switch (note->descsz)
2545c074d1c9Sdrahn     {
2546c074d1c9Sdrahn       default:
2547c074d1c9Sdrahn 	return FALSE;
2548c074d1c9Sdrahn 
2549c074d1c9Sdrahn       case 480:		/* Linux/MIPS - N64 kernel */
2550c074d1c9Sdrahn 	/* pr_cursig */
2551c074d1c9Sdrahn 	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
2552c074d1c9Sdrahn 
2553c074d1c9Sdrahn 	/* pr_pid */
2554c074d1c9Sdrahn 	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 32);
2555c074d1c9Sdrahn 
2556c074d1c9Sdrahn 	/* pr_reg */
2557c074d1c9Sdrahn 	offset = 112;
2558c074d1c9Sdrahn 	raw_size = 360;
2559c074d1c9Sdrahn 
2560c074d1c9Sdrahn 	break;
25614361b62eSniklas     }
25624361b62eSniklas 
2563c074d1c9Sdrahn   /* Make a ".reg/999" section.  */
2564c074d1c9Sdrahn   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
2565c074d1c9Sdrahn 					  raw_size, note->descpos + offset);
25664361b62eSniklas }
25674361b62eSniklas 
2568c074d1c9Sdrahn static bfd_boolean
elf64_mips_grok_psinfo(bfd * abfd,Elf_Internal_Note * note)2569*007c2a45Smiod elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
25704361b62eSniklas {
2571c074d1c9Sdrahn   switch (note->descsz)
2572c074d1c9Sdrahn     {
2573c074d1c9Sdrahn       default:
2574c074d1c9Sdrahn 	return FALSE;
25754361b62eSniklas 
2576c074d1c9Sdrahn       case 136:		/* Linux/MIPS - N64 kernel elf_prpsinfo */
2577c074d1c9Sdrahn 	elf_tdata (abfd)->core_program
2578c074d1c9Sdrahn 	 = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
2579c074d1c9Sdrahn 	elf_tdata (abfd)->core_command
2580c074d1c9Sdrahn 	 = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
25814361b62eSniklas     }
25824361b62eSniklas 
2583c074d1c9Sdrahn   /* Note that for some reason, a spurious space is tacked
2584c074d1c9Sdrahn      onto the end of the args in some (at least one anyway)
2585c074d1c9Sdrahn      implementations, so strip it off if it exists.  */
25864361b62eSniklas 
25874361b62eSniklas   {
2588c074d1c9Sdrahn     char *command = elf_tdata (abfd)->core_command;
2589c074d1c9Sdrahn     int n = strlen (command);
25904361b62eSniklas 
2591c074d1c9Sdrahn     if (0 < n && command[n - 1] == ' ')
2592c074d1c9Sdrahn       command[n - 1] = '\0';
25934361b62eSniklas   }
25944361b62eSniklas 
2595c074d1c9Sdrahn   return TRUE;
25964361b62eSniklas }
25974361b62eSniklas 
2598c88b1d6cSniklas /* ECOFF swapping routines.  These are used when dealing with the
2599c88b1d6cSniklas    .mdebug section, which is in the ECOFF debugging format.  */
2600c88b1d6cSniklas static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap =
2601c88b1d6cSniklas {
2602c88b1d6cSniklas   /* Symbol table magic number.  */
2603c88b1d6cSniklas   magicSym2,
2604c88b1d6cSniklas   /* Alignment of debugging information.  E.g., 4.  */
2605c88b1d6cSniklas   8,
2606c88b1d6cSniklas   /* Sizes of external symbolic information.  */
2607c88b1d6cSniklas   sizeof (struct hdr_ext),
2608c88b1d6cSniklas   sizeof (struct dnr_ext),
2609c88b1d6cSniklas   sizeof (struct pdr_ext),
2610c88b1d6cSniklas   sizeof (struct sym_ext),
2611c88b1d6cSniklas   sizeof (struct opt_ext),
2612c88b1d6cSniklas   sizeof (struct fdr_ext),
2613c88b1d6cSniklas   sizeof (struct rfd_ext),
2614c88b1d6cSniklas   sizeof (struct ext_ext),
2615c88b1d6cSniklas   /* Functions to swap in external symbolic data.  */
2616c88b1d6cSniklas   ecoff_swap_hdr_in,
2617c88b1d6cSniklas   ecoff_swap_dnr_in,
2618c88b1d6cSniklas   ecoff_swap_pdr_in,
2619c88b1d6cSniklas   ecoff_swap_sym_in,
2620c88b1d6cSniklas   ecoff_swap_opt_in,
2621c88b1d6cSniklas   ecoff_swap_fdr_in,
2622c88b1d6cSniklas   ecoff_swap_rfd_in,
2623c88b1d6cSniklas   ecoff_swap_ext_in,
2624c88b1d6cSniklas   _bfd_ecoff_swap_tir_in,
2625c88b1d6cSniklas   _bfd_ecoff_swap_rndx_in,
2626c88b1d6cSniklas   /* Functions to swap out external symbolic data.  */
2627c88b1d6cSniklas   ecoff_swap_hdr_out,
2628c88b1d6cSniklas   ecoff_swap_dnr_out,
2629c88b1d6cSniklas   ecoff_swap_pdr_out,
2630c88b1d6cSniklas   ecoff_swap_sym_out,
2631c88b1d6cSniklas   ecoff_swap_opt_out,
2632c88b1d6cSniklas   ecoff_swap_fdr_out,
2633c88b1d6cSniklas   ecoff_swap_rfd_out,
2634c88b1d6cSniklas   ecoff_swap_ext_out,
2635c88b1d6cSniklas   _bfd_ecoff_swap_tir_out,
2636c88b1d6cSniklas   _bfd_ecoff_swap_rndx_out,
2637c88b1d6cSniklas   /* Function to read in symbolic data.  */
2638c88b1d6cSniklas   _bfd_mips_elf_read_ecoff_info
2639c88b1d6cSniklas };
2640c88b1d6cSniklas 
2641c88b1d6cSniklas /* Relocations in the 64 bit MIPS ELF ABI are more complex than in
2642c88b1d6cSniklas    standard ELF.  This structure is used to redirect the relocation
2643c88b1d6cSniklas    handling routines.  */
2644c88b1d6cSniklas 
2645c88b1d6cSniklas const struct elf_size_info mips_elf64_size_info =
2646c88b1d6cSniklas {
2647c88b1d6cSniklas   sizeof (Elf64_External_Ehdr),
2648c88b1d6cSniklas   sizeof (Elf64_External_Phdr),
2649c88b1d6cSniklas   sizeof (Elf64_External_Shdr),
2650c88b1d6cSniklas   sizeof (Elf64_Mips_External_Rel),
2651c88b1d6cSniklas   sizeof (Elf64_Mips_External_Rela),
2652c88b1d6cSniklas   sizeof (Elf64_External_Sym),
2653c88b1d6cSniklas   sizeof (Elf64_External_Dyn),
2654c88b1d6cSniklas   sizeof (Elf_External_Note),
2655b305b0f1Sespie   4,            /* hash-table entry size */
2656b305b0f1Sespie   3,            /* internal relocations per external relocations */
2657c88b1d6cSniklas   64,		/* arch_size */
2658*007c2a45Smiod   3,		/* log_file_align */
2659c88b1d6cSniklas   ELFCLASS64,
2660c88b1d6cSniklas   EV_CURRENT,
2661c88b1d6cSniklas   bfd_elf64_write_out_phdrs,
2662c88b1d6cSniklas   bfd_elf64_write_shdrs_and_ehdr,
2663c88b1d6cSniklas   mips_elf64_write_relocs,
2664c074d1c9Sdrahn   bfd_elf64_swap_symbol_in,
2665c88b1d6cSniklas   bfd_elf64_swap_symbol_out,
2666c88b1d6cSniklas   mips_elf64_slurp_reloc_table,
2667c88b1d6cSniklas   bfd_elf64_slurp_symbol_table,
2668b305b0f1Sespie   bfd_elf64_swap_dyn_in,
2669b305b0f1Sespie   bfd_elf64_swap_dyn_out,
2670b305b0f1Sespie   mips_elf64_be_swap_reloc_in,
2671b305b0f1Sespie   mips_elf64_be_swap_reloc_out,
2672b305b0f1Sespie   mips_elf64_be_swap_reloca_in,
2673b305b0f1Sespie   mips_elf64_be_swap_reloca_out
2674c88b1d6cSniklas };
2675c88b1d6cSniklas 
2676c88b1d6cSniklas #define ELF_ARCH			bfd_arch_mips
2677c88b1d6cSniklas #define ELF_MACHINE_CODE		EM_MIPS
2678b305b0f1Sespie 
2679c074d1c9Sdrahn #define elf_backend_collect		TRUE
2680c074d1c9Sdrahn #define elf_backend_type_change_ok	TRUE
2681c074d1c9Sdrahn #define elf_backend_can_gc_sections	TRUE
2682c074d1c9Sdrahn #define elf_info_to_howto		mips_elf64_info_to_howto_rela
2683c074d1c9Sdrahn #define elf_info_to_howto_rel		mips_elf64_info_to_howto_rel
2684c074d1c9Sdrahn #define elf_backend_object_p		mips_elf64_object_p
2685c074d1c9Sdrahn #define elf_backend_symbol_processing	_bfd_mips_elf_symbol_processing
2686c074d1c9Sdrahn #define elf_backend_section_processing	_bfd_mips_elf_section_processing
2687b305b0f1Sespie #define elf_backend_section_from_shdr	_bfd_mips_elf_section_from_shdr
2688c88b1d6cSniklas #define elf_backend_fake_sections	_bfd_mips_elf_fake_sections
2689c88b1d6cSniklas #define elf_backend_section_from_bfd_section \
2690c88b1d6cSniklas 				_bfd_mips_elf_section_from_bfd_section
2691b305b0f1Sespie #define elf_backend_add_symbol_hook	_bfd_mips_elf_add_symbol_hook
2692c074d1c9Sdrahn #define elf_backend_link_output_symbol_hook \
2693c074d1c9Sdrahn 				_bfd_mips_elf_link_output_symbol_hook
2694b305b0f1Sespie #define elf_backend_create_dynamic_sections \
2695b305b0f1Sespie 				_bfd_mips_elf_create_dynamic_sections
2696b305b0f1Sespie #define elf_backend_check_relocs	_bfd_mips_elf_check_relocs
2697b305b0f1Sespie #define elf_backend_adjust_dynamic_symbol \
2698b305b0f1Sespie 				_bfd_mips_elf_adjust_dynamic_symbol
2699b305b0f1Sespie #define elf_backend_always_size_sections \
2700b305b0f1Sespie 				_bfd_mips_elf_always_size_sections
2701b305b0f1Sespie #define elf_backend_size_dynamic_sections \
2702b305b0f1Sespie 				_bfd_mips_elf_size_dynamic_sections
2703b305b0f1Sespie #define elf_backend_relocate_section    _bfd_mips_elf_relocate_section
2704b305b0f1Sespie #define elf_backend_finish_dynamic_symbol \
2705b305b0f1Sespie 				_bfd_mips_elf_finish_dynamic_symbol
2706b305b0f1Sespie #define elf_backend_finish_dynamic_sections \
2707b305b0f1Sespie 				_bfd_mips_elf_finish_dynamic_sections
2708c074d1c9Sdrahn #define elf_backend_final_write_processing \
2709c074d1c9Sdrahn 				_bfd_mips_elf_final_write_processing
2710c074d1c9Sdrahn #define elf_backend_additional_program_headers \
2711c074d1c9Sdrahn 				_bfd_mips_elf_additional_program_headers
2712c074d1c9Sdrahn #define elf_backend_modify_segment_map	_bfd_mips_elf_modify_segment_map
2713b305b0f1Sespie #define elf_backend_gc_mark_hook	_bfd_mips_elf_gc_mark_hook
2714b305b0f1Sespie #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
2715*007c2a45Smiod #define elf_backend_copy_indirect_symbol \
2716*007c2a45Smiod 					_bfd_mips_elf_copy_indirect_symbol
2717c074d1c9Sdrahn #define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
2718c074d1c9Sdrahn #define elf_backend_ignore_discarded_relocs \
2719c074d1c9Sdrahn 					_bfd_mips_elf_ignore_discarded_relocs
2720c074d1c9Sdrahn #define elf_backend_mips_irix_compat	elf64_mips_irix_compat
2721c074d1c9Sdrahn #define elf_backend_mips_rtype_to_howto	mips_elf64_rtype_to_howto
2722c074d1c9Sdrahn #define elf_backend_ecoff_debug_swap	&mips_elf64_ecoff_debug_swap
2723c074d1c9Sdrahn #define elf_backend_size_info		mips_elf64_size_info
2724c074d1c9Sdrahn 
2725c074d1c9Sdrahn #define elf_backend_grok_prstatus	elf64_mips_grok_prstatus
2726c074d1c9Sdrahn #define elf_backend_grok_psinfo		elf64_mips_grok_psinfo
2727c074d1c9Sdrahn 
2728b305b0f1Sespie #define elf_backend_got_header_size	(4 * MIPS_RESERVED_GOTNO)
2729c074d1c9Sdrahn 
2730c074d1c9Sdrahn /* MIPS ELF64 can use a mixture of REL and RELA, but some Relocations
2731c074d1c9Sdrahn    work better/work only in RELA, so we default to this.  */
2732b305b0f1Sespie #define elf_backend_may_use_rel_p	1
2733c074d1c9Sdrahn #define elf_backend_may_use_rela_p	1
2734c074d1c9Sdrahn #define elf_backend_default_use_rela_p	1
2735c074d1c9Sdrahn 
2736c074d1c9Sdrahn #define elf_backend_write_section	_bfd_mips_elf_write_section
2737c88b1d6cSniklas 
2738b305b0f1Sespie /* We don't set bfd_elf64_bfd_is_local_label_name because the 32-bit
2739b305b0f1Sespie    MIPS-specific function only applies to IRIX5, which had no 64-bit
2740b305b0f1Sespie    ABI.  */
2741c88b1d6cSniklas #define bfd_elf64_find_nearest_line	_bfd_mips_elf_find_nearest_line
2742c074d1c9Sdrahn #define bfd_elf64_new_section_hook	_bfd_mips_elf_new_section_hook
2743c88b1d6cSniklas #define bfd_elf64_set_section_contents	_bfd_mips_elf_set_section_contents
2744c074d1c9Sdrahn #define bfd_elf64_bfd_get_relocated_section_contents \
2745c074d1c9Sdrahn 				_bfd_elf_mips_get_relocated_section_contents
2746b305b0f1Sespie #define bfd_elf64_bfd_link_hash_table_create \
2747b305b0f1Sespie 				_bfd_mips_elf_link_hash_table_create
2748b305b0f1Sespie #define bfd_elf64_bfd_final_link	_bfd_mips_elf_final_link
2749c88b1d6cSniklas #define bfd_elf64_bfd_merge_private_bfd_data \
2750c88b1d6cSniklas 				_bfd_mips_elf_merge_private_bfd_data
2751c88b1d6cSniklas #define bfd_elf64_bfd_set_private_flags	_bfd_mips_elf_set_private_flags
2752b305b0f1Sespie #define bfd_elf64_bfd_print_private_bfd_data \
2753b305b0f1Sespie 				_bfd_mips_elf_print_private_bfd_data
2754c88b1d6cSniklas 
2755b305b0f1Sespie #define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
2756c074d1c9Sdrahn #define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
2757c074d1c9Sdrahn #define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
2758c074d1c9Sdrahn #define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
2759c074d1c9Sdrahn #define bfd_elf64_bfd_relax_section     _bfd_mips_relax_section
2760c074d1c9Sdrahn 
2761c074d1c9Sdrahn /* MIPS ELF64 archive functions.  */
27624361b62eSniklas #define bfd_elf64_archive_functions
2763c074d1c9Sdrahn extern bfd_boolean bfd_elf64_archive_slurp_armap
2764*007c2a45Smiod   (bfd *);
2765c074d1c9Sdrahn extern bfd_boolean bfd_elf64_archive_write_armap
2766*007c2a45Smiod   (bfd *, unsigned int, struct orl *, unsigned int, int);
27674361b62eSniklas #define bfd_elf64_archive_slurp_extended_name_table \
27684361b62eSniklas 			_bfd_archive_coff_slurp_extended_name_table
27694361b62eSniklas #define bfd_elf64_archive_construct_extended_name_table \
27704361b62eSniklas 			_bfd_archive_coff_construct_extended_name_table
27714361b62eSniklas #define bfd_elf64_archive_truncate_arname \
27724361b62eSniklas 			_bfd_archive_coff_truncate_arname
27734361b62eSniklas #define bfd_elf64_archive_read_ar_hdr	_bfd_archive_coff_read_ar_hdr
27744361b62eSniklas #define bfd_elf64_archive_openr_next_archived_file \
27754361b62eSniklas 			_bfd_archive_coff_openr_next_archived_file
27764361b62eSniklas #define bfd_elf64_archive_get_elt_at_index \
27774361b62eSniklas 			_bfd_archive_coff_get_elt_at_index
27784361b62eSniklas #define bfd_elf64_archive_generic_stat_arch_elt \
27794361b62eSniklas 			_bfd_archive_coff_generic_stat_arch_elt
27804361b62eSniklas #define bfd_elf64_archive_update_armap_timestamp \
27814361b62eSniklas 			_bfd_archive_coff_update_armap_timestamp
27824361b62eSniklas 
2783c074d1c9Sdrahn /* The SGI style (n)64 NewABI.  */
2784c074d1c9Sdrahn #define TARGET_LITTLE_SYM		bfd_elf64_littlemips_vec
2785c074d1c9Sdrahn #define TARGET_LITTLE_NAME		"elf64-littlemips"
2786c074d1c9Sdrahn #define TARGET_BIG_SYM			bfd_elf64_bigmips_vec
2787c074d1c9Sdrahn #define TARGET_BIG_NAME			"elf64-bigmips"
2788c074d1c9Sdrahn 
2789*007c2a45Smiod /* The SVR4 MIPS ABI says that this should be 0x10000, but Irix 5 uses
2790*007c2a45Smiod    a value of 0x1000, and we are compatible.
2791*007c2a45Smiod    FIXME: How does this affect NewABI?  */
2792*007c2a45Smiod #define ELF_MAXPAGESIZE			0x1000
2793b55d4692Sfgsch 
2794*007c2a45Smiod #include "elf64-target.h"
2795b55d4692Sfgsch 
2796c074d1c9Sdrahn /* The SYSV-style 'traditional' (n)64 NewABI.  */
2797b55d4692Sfgsch #undef TARGET_LITTLE_SYM
2798b55d4692Sfgsch #undef TARGET_LITTLE_NAME
2799b55d4692Sfgsch #undef TARGET_BIG_SYM
2800b55d4692Sfgsch #undef TARGET_BIG_NAME
2801b55d4692Sfgsch 
2802*007c2a45Smiod #undef ELF_MAXPAGESIZE
2803*007c2a45Smiod 
2804b55d4692Sfgsch #define TARGET_LITTLE_SYM               bfd_elf64_tradlittlemips_vec
2805b55d4692Sfgsch #define TARGET_LITTLE_NAME              "elf64-tradlittlemips"
2806b55d4692Sfgsch #define TARGET_BIG_SYM                  bfd_elf64_tradbigmips_vec
2807b55d4692Sfgsch #define TARGET_BIG_NAME                 "elf64-tradbigmips"
2808b55d4692Sfgsch 
2809*007c2a45Smiod /* The SVR4 MIPS ABI says that this should be 0x10000, and Linux uses
2810*007c2a45Smiod    page sizes of up to that limit, so we need to respect it.  */
2811*007c2a45Smiod #define ELF_MAXPAGESIZE			0x10000
2812*007c2a45Smiod #define elf64_bed			elf64_tradbed
2813*007c2a45Smiod 
2814c074d1c9Sdrahn /* Include the target file again for this target.  */
2815b55d4692Sfgsch #include "elf64-target.h"
2816