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