1179407Sobrien/* MIPS-specific support for 32-bit ELF
2179407Sobrien   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3218822Sdim   2003, 2004, 2005, 2007 Free Software Foundation, Inc.
4179407Sobrien
5179407Sobrien   Most of the information added by Ian Lance Taylor, Cygnus Support,
6179407Sobrien   <ian@cygnus.com>.
7179407Sobrien   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
8179407Sobrien   <mark@codesourcery.com>
9179407Sobrien   Traditional MIPS targets support added by Koundinya.K, Dansk Data
10179407Sobrien   Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
11179407Sobrien
12179407SobrienThis file is part of BFD, the Binary File Descriptor library.
13179407Sobrien
14179407SobrienThis program is free software; you can redistribute it and/or modify
15179407Sobrienit under the terms of the GNU General Public License as published by
16179407Sobrienthe Free Software Foundation; either version 2 of the License, or
17179407Sobrien(at your option) any later version.
18179407Sobrien
19179407SobrienThis program is distributed in the hope that it will be useful,
20179407Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
21179407SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22179407SobrienGNU General Public License for more details.
23179407Sobrien
24179407SobrienYou should have received a copy of the GNU General Public License
25179407Sobrienalong with this program; if not, write to the Free Software
26218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
27179407Sobrien
28179407Sobrien/* This file handles MIPS ELF targets.  SGI Irix 5 uses a slightly
29179407Sobrien   different MIPS ELF from other targets.  This matters when linking.
30179407Sobrien   This file supports both, switching at runtime.  */
31179407Sobrien
32218822Sdim#include "sysdep.h"
33179407Sobrien#include "bfd.h"
34179407Sobrien#include "libbfd.h"
35179407Sobrien#include "bfdlink.h"
36179407Sobrien#include "genlink.h"
37179407Sobrien#include "elf-bfd.h"
38179407Sobrien#include "elfxx-mips.h"
39179407Sobrien#include "elf/mips.h"
40218822Sdim#include "elf-vxworks.h"
41179407Sobrien
42179407Sobrien/* Get the ECOFF swapping routines.  */
43179407Sobrien#include "coff/sym.h"
44179407Sobrien#include "coff/symconst.h"
45179407Sobrien#include "coff/internal.h"
46179407Sobrien#include "coff/ecoff.h"
47179407Sobrien#include "coff/mips.h"
48179407Sobrien#define ECOFF_SIGNED_32
49179407Sobrien#include "ecoffswap.h"
50179407Sobrien
51179407Sobrienstatic bfd_reloc_status_type gprel32_with_gp
52179407Sobrien  (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma);
53179407Sobrienstatic bfd_reloc_status_type mips_elf_gprel32_reloc
54179407Sobrien  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55179407Sobrienstatic bfd_reloc_status_type mips32_64bit_reloc
56179407Sobrien  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
57179407Sobrienstatic reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
58179407Sobrien  (bfd *, bfd_reloc_code_real_type);
59179407Sobrienstatic reloc_howto_type *mips_elf32_rtype_to_howto
60179407Sobrien  (unsigned int, bfd_boolean);
61179407Sobrienstatic void mips_info_to_howto_rel
62179407Sobrien  (bfd *, arelent *, Elf_Internal_Rela *);
63179407Sobrienstatic void mips_info_to_howto_rela
64179407Sobrien  (bfd *, arelent *, Elf_Internal_Rela *);
65179407Sobrienstatic bfd_boolean mips_elf_sym_is_global
66179407Sobrien  (bfd *, asymbol *);
67179407Sobrienstatic bfd_boolean mips_elf32_object_p
68179407Sobrien  (bfd *);
69179407Sobrienstatic bfd_boolean mips_elf_is_local_label_name
70179407Sobrien  (bfd *, const char *);
71179407Sobrienstatic bfd_reloc_status_type mips16_gprel_reloc
72179407Sobrien  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
73179407Sobrienstatic bfd_reloc_status_type mips_elf_final_gp
74179407Sobrien  (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
75179407Sobrienstatic bfd_boolean mips_elf_assign_gp
76179407Sobrien  (bfd *, bfd_vma *);
77179407Sobrienstatic bfd_boolean elf32_mips_grok_prstatus
78179407Sobrien  (bfd *, Elf_Internal_Note *);
79179407Sobrienstatic bfd_boolean elf32_mips_grok_psinfo
80179407Sobrien  (bfd *, Elf_Internal_Note *);
81179407Sobrienstatic irix_compat_t elf32_mips_irix_compat
82179407Sobrien  (bfd *);
83179407Sobrien
84179407Sobrienextern const bfd_target bfd_elf32_bigmips_vec;
85179407Sobrienextern const bfd_target bfd_elf32_littlemips_vec;
86179407Sobrien
87179407Sobrien/* Nonzero if ABFD is using the N32 ABI.  */
88179407Sobrien#define ABI_N32_P(abfd) \
89179407Sobrien  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
90179407Sobrien
91179407Sobrien/* Whether we are trying to be compatible with IRIX at all.  */
92179407Sobrien#define SGI_COMPAT(abfd) \
93179407Sobrien  (elf32_mips_irix_compat (abfd) != ict_none)
94179407Sobrien
95179407Sobrien/* The number of local .got entries we reserve.  */
96179407Sobrien#define MIPS_RESERVED_GOTNO (2)
97179407Sobrien
98179407Sobrien/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
99179407Sobrien   from smaller values.  Start with zero, widen, *then* decrement.  */
100179407Sobrien#define MINUS_ONE	(((bfd_vma)0) - 1)
101179407Sobrien
102179407Sobrien/* The relocation table used for SHT_REL sections.  */
103179407Sobrien
104179407Sobrienstatic reloc_howto_type elf_mips_howto_table_rel[] =
105179407Sobrien{
106179407Sobrien  /* No relocation.  */
107179407Sobrien  HOWTO (R_MIPS_NONE,		/* type */
108179407Sobrien	 0,			/* rightshift */
109179407Sobrien	 0,			/* size (0 = byte, 1 = short, 2 = long) */
110179407Sobrien	 0,			/* bitsize */
111179407Sobrien	 FALSE,			/* pc_relative */
112179407Sobrien	 0,			/* bitpos */
113179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
114179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
115179407Sobrien	 "R_MIPS_NONE",		/* name */
116179407Sobrien	 FALSE,			/* partial_inplace */
117179407Sobrien	 0,			/* src_mask */
118179407Sobrien	 0,			/* dst_mask */
119179407Sobrien	 FALSE),		/* pcrel_offset */
120179407Sobrien
121179407Sobrien  /* 16 bit relocation.  */
122179407Sobrien  HOWTO (R_MIPS_16,		/* type */
123179407Sobrien	 0,			/* rightshift */
124179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
125179407Sobrien	 16,			/* bitsize */
126179407Sobrien	 FALSE,			/* pc_relative */
127179407Sobrien	 0,			/* bitpos */
128179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
129179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
130179407Sobrien	 "R_MIPS_16",		/* name */
131179407Sobrien	 TRUE,			/* partial_inplace */
132179407Sobrien	 0x0000ffff,		/* src_mask */
133179407Sobrien	 0x0000ffff,		/* dst_mask */
134179407Sobrien	 FALSE),		/* pcrel_offset */
135179407Sobrien
136179407Sobrien  /* 32 bit relocation.  */
137179407Sobrien  HOWTO (R_MIPS_32,		/* type */
138179407Sobrien	 0,			/* rightshift */
139179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
140179407Sobrien	 32,			/* bitsize */
141179407Sobrien	 FALSE,			/* pc_relative */
142179407Sobrien	 0,			/* bitpos */
143179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
144179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
145179407Sobrien	 "R_MIPS_32",		/* name */
146179407Sobrien	 TRUE,			/* partial_inplace */
147179407Sobrien	 0xffffffff,		/* src_mask */
148179407Sobrien	 0xffffffff,		/* dst_mask */
149179407Sobrien	 FALSE),		/* pcrel_offset */
150179407Sobrien
151179407Sobrien  /* 32 bit symbol relative relocation.  */
152179407Sobrien  HOWTO (R_MIPS_REL32,		/* type */
153179407Sobrien	 0,			/* rightshift */
154179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
155179407Sobrien	 32,			/* bitsize */
156179407Sobrien	 FALSE,			/* pc_relative */
157179407Sobrien	 0,			/* bitpos */
158179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
159179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
160179407Sobrien	 "R_MIPS_REL32",	/* name */
161179407Sobrien	 TRUE,			/* partial_inplace */
162179407Sobrien	 0xffffffff,		/* src_mask */
163179407Sobrien	 0xffffffff,		/* dst_mask */
164179407Sobrien	 FALSE),		/* pcrel_offset */
165179407Sobrien
166179407Sobrien  /* 26 bit jump address.  */
167179407Sobrien  HOWTO (R_MIPS_26,		/* type */
168179407Sobrien	 2,			/* rightshift */
169179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
170179407Sobrien	 26,			/* bitsize */
171179407Sobrien	 FALSE,			/* pc_relative */
172179407Sobrien	 0,			/* bitpos */
173179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
174179407Sobrien	 			/* This needs complex overflow
175179407Sobrien				   detection, because the upper four
176179407Sobrien				   bits must match the PC + 4.  */
177179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
178179407Sobrien	 "R_MIPS_26",		/* name */
179179407Sobrien	 TRUE,			/* partial_inplace */
180179407Sobrien	 0x03ffffff,		/* src_mask */
181179407Sobrien	 0x03ffffff,		/* dst_mask */
182179407Sobrien	 FALSE),		/* pcrel_offset */
183179407Sobrien
184179407Sobrien  /* High 16 bits of symbol value.  */
185179407Sobrien  HOWTO (R_MIPS_HI16,		/* type */
186179407Sobrien	 16,			/* rightshift */
187179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
188179407Sobrien	 16,			/* bitsize */
189179407Sobrien	 FALSE,			/* pc_relative */
190179407Sobrien	 0,			/* bitpos */
191179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
192179407Sobrien	 _bfd_mips_elf_hi16_reloc, /* special_function */
193179407Sobrien	 "R_MIPS_HI16",		/* name */
194179407Sobrien	 TRUE,			/* partial_inplace */
195179407Sobrien	 0x0000ffff,		/* src_mask */
196179407Sobrien	 0x0000ffff,		/* dst_mask */
197179407Sobrien	 FALSE),		/* pcrel_offset */
198179407Sobrien
199179407Sobrien  /* Low 16 bits of symbol value.  */
200179407Sobrien  HOWTO (R_MIPS_LO16,		/* type */
201179407Sobrien	 0,			/* rightshift */
202179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
203179407Sobrien	 16,			/* bitsize */
204179407Sobrien	 FALSE,			/* pc_relative */
205179407Sobrien	 0,			/* bitpos */
206179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
207179407Sobrien	 _bfd_mips_elf_lo16_reloc, /* special_function */
208179407Sobrien	 "R_MIPS_LO16",		/* name */
209179407Sobrien	 TRUE,			/* partial_inplace */
210179407Sobrien	 0x0000ffff,		/* src_mask */
211179407Sobrien	 0x0000ffff,		/* dst_mask */
212179407Sobrien	 FALSE),		/* pcrel_offset */
213179407Sobrien
214179407Sobrien  /* GP relative reference.  */
215179407Sobrien  HOWTO (R_MIPS_GPREL16,	/* type */
216179407Sobrien	 0,			/* rightshift */
217179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
218179407Sobrien	 16,			/* bitsize */
219179407Sobrien	 FALSE,			/* pc_relative */
220179407Sobrien	 0,			/* bitpos */
221179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
222179407Sobrien	 _bfd_mips_elf32_gprel16_reloc, /* special_function */
223179407Sobrien	 "R_MIPS_GPREL16",	/* name */
224179407Sobrien	 TRUE,			/* partial_inplace */
225179407Sobrien	 0x0000ffff,		/* src_mask */
226179407Sobrien	 0x0000ffff,		/* dst_mask */
227179407Sobrien	 FALSE),		/* pcrel_offset */
228179407Sobrien
229179407Sobrien  /* Reference to literal section.  */
230179407Sobrien  HOWTO (R_MIPS_LITERAL,	/* type */
231179407Sobrien	 0,			/* rightshift */
232179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
233179407Sobrien	 16,			/* bitsize */
234179407Sobrien	 FALSE,			/* pc_relative */
235179407Sobrien	 0,			/* bitpos */
236179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
237179407Sobrien	 _bfd_mips_elf32_gprel16_reloc, /* special_function */
238179407Sobrien	 "R_MIPS_LITERAL",	/* name */
239179407Sobrien	 TRUE,			/* partial_inplace */
240179407Sobrien	 0x0000ffff,		/* src_mask */
241179407Sobrien	 0x0000ffff,		/* dst_mask */
242179407Sobrien	 FALSE),		/* pcrel_offset */
243179407Sobrien
244179407Sobrien  /* Reference to global offset table.  */
245179407Sobrien  HOWTO (R_MIPS_GOT16,		/* type */
246179407Sobrien	 0,			/* rightshift */
247179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
248179407Sobrien	 16,			/* bitsize */
249179407Sobrien	 FALSE,			/* pc_relative */
250179407Sobrien	 0,			/* bitpos */
251179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
252179407Sobrien	 _bfd_mips_elf_got16_reloc, /* special_function */
253179407Sobrien	 "R_MIPS_GOT16",	/* name */
254179407Sobrien	 TRUE,			/* partial_inplace */
255179407Sobrien	 0x0000ffff,		/* src_mask */
256179407Sobrien	 0x0000ffff,		/* dst_mask */
257179407Sobrien	 FALSE),		/* pcrel_offset */
258179407Sobrien
259218822Sdim  /* 16 bit PC relative reference.  Note that the ABI document has a typo
260218822Sdim     and claims R_MIPS_PC16 to be not rightshifted, rendering it useless.
261218822Sdim     We do the right thing here.  */
262179407Sobrien  HOWTO (R_MIPS_PC16,		/* type */
263218822Sdim	 2,			/* rightshift */
264179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
265179407Sobrien	 16,			/* bitsize */
266179407Sobrien	 TRUE,			/* pc_relative */
267179407Sobrien	 0,			/* bitpos */
268179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
269179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
270179407Sobrien	 "R_MIPS_PC16",		/* name */
271179407Sobrien	 TRUE,			/* partial_inplace */
272179407Sobrien	 0x0000ffff,		/* src_mask */
273179407Sobrien	 0x0000ffff,		/* dst_mask */
274179407Sobrien	 TRUE),			/* pcrel_offset */
275179407Sobrien
276179407Sobrien  /* 16 bit call through global offset table.  */
277179407Sobrien  HOWTO (R_MIPS_CALL16,		/* type */
278179407Sobrien	 0,			/* rightshift */
279179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
280179407Sobrien	 16,			/* bitsize */
281179407Sobrien	 FALSE,			/* pc_relative */
282179407Sobrien	 0,			/* bitpos */
283179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
284179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
285179407Sobrien	 "R_MIPS_CALL16",	/* name */
286179407Sobrien	 TRUE,			/* partial_inplace */
287179407Sobrien	 0x0000ffff,		/* src_mask */
288179407Sobrien	 0x0000ffff,		/* dst_mask */
289179407Sobrien	 FALSE),		/* pcrel_offset */
290179407Sobrien
291179407Sobrien  /* 32 bit GP relative reference.  */
292179407Sobrien  HOWTO (R_MIPS_GPREL32,	/* type */
293179407Sobrien	 0,			/* rightshift */
294179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
295179407Sobrien	 32,			/* bitsize */
296179407Sobrien	 FALSE,			/* pc_relative */
297179407Sobrien	 0,			/* bitpos */
298179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
299179407Sobrien	 mips_elf_gprel32_reloc, /* special_function */
300179407Sobrien	 "R_MIPS_GPREL32",	/* name */
301179407Sobrien	 TRUE,			/* partial_inplace */
302179407Sobrien	 0xffffffff,		/* src_mask */
303179407Sobrien	 0xffffffff,		/* dst_mask */
304179407Sobrien	 FALSE),		/* pcrel_offset */
305179407Sobrien
306179407Sobrien  /* The remaining relocs are defined on Irix 5, although they are
307179407Sobrien     not defined by the ABI.  */
308179407Sobrien  EMPTY_HOWTO (13),
309179407Sobrien  EMPTY_HOWTO (14),
310179407Sobrien  EMPTY_HOWTO (15),
311179407Sobrien
312179407Sobrien  /* A 5 bit shift field.  */
313179407Sobrien  HOWTO (R_MIPS_SHIFT5,		/* type */
314179407Sobrien	 0,			/* rightshift */
315179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
316179407Sobrien	 5,			/* bitsize */
317179407Sobrien	 FALSE,			/* pc_relative */
318179407Sobrien	 6,			/* bitpos */
319179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
320179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
321179407Sobrien	 "R_MIPS_SHIFT5",	/* name */
322179407Sobrien	 TRUE,			/* partial_inplace */
323179407Sobrien	 0x000007c0,		/* src_mask */
324179407Sobrien	 0x000007c0,		/* dst_mask */
325179407Sobrien	 FALSE),		/* pcrel_offset */
326179407Sobrien
327179407Sobrien  /* A 6 bit shift field.  */
328179407Sobrien  /* FIXME: This is not handled correctly; a special function is
329179407Sobrien     needed to put the most significant bit in the right place.  */
330179407Sobrien  HOWTO (R_MIPS_SHIFT6,		/* type */
331179407Sobrien	 0,			/* rightshift */
332179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
333179407Sobrien	 6,			/* bitsize */
334179407Sobrien	 FALSE,			/* pc_relative */
335179407Sobrien	 6,			/* bitpos */
336179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
337179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
338179407Sobrien	 "R_MIPS_SHIFT6",	/* name */
339179407Sobrien	 TRUE,			/* partial_inplace */
340179407Sobrien	 0x000007c4,		/* src_mask */
341179407Sobrien	 0x000007c4,		/* dst_mask */
342179407Sobrien	 FALSE),		/* pcrel_offset */
343179407Sobrien
344179407Sobrien  /* A 64 bit relocation.  */
345179407Sobrien  HOWTO (R_MIPS_64,		/* type */
346179407Sobrien	 0,			/* rightshift */
347179407Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
348179407Sobrien	 64,			/* bitsize */
349179407Sobrien	 FALSE,			/* pc_relative */
350179407Sobrien	 0,			/* bitpos */
351179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
352179407Sobrien	 mips32_64bit_reloc,	/* special_function */
353179407Sobrien	 "R_MIPS_64",		/* name */
354179407Sobrien	 TRUE,			/* partial_inplace */
355179407Sobrien	 MINUS_ONE,		/* src_mask */
356179407Sobrien	 MINUS_ONE,		/* dst_mask */
357179407Sobrien	 FALSE),		/* pcrel_offset */
358179407Sobrien
359179407Sobrien  /* Displacement in the global offset table.  */
360179407Sobrien  HOWTO (R_MIPS_GOT_DISP,	/* type */
361179407Sobrien	 0,			/* rightshift */
362179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
363179407Sobrien	 16,			/* bitsize */
364179407Sobrien	 FALSE,			/* pc_relative */
365179407Sobrien	 0,			/* bitpos */
366179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
367179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
368179407Sobrien	 "R_MIPS_GOT_DISP",	/* name */
369179407Sobrien	 TRUE,			/* partial_inplace */
370179407Sobrien	 0x0000ffff,		/* src_mask */
371179407Sobrien	 0x0000ffff,		/* dst_mask */
372179407Sobrien	 FALSE),		/* pcrel_offset */
373179407Sobrien
374179407Sobrien  /* Displacement to page pointer in the global offset table.  */
375179407Sobrien  HOWTO (R_MIPS_GOT_PAGE,	/* type */
376179407Sobrien	 0,			/* rightshift */
377179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
378179407Sobrien	 16,			/* bitsize */
379179407Sobrien	 FALSE,			/* pc_relative */
380179407Sobrien	 0,			/* bitpos */
381179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
382179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
383179407Sobrien	 "R_MIPS_GOT_PAGE",	/* name */
384179407Sobrien	 TRUE,			/* partial_inplace */
385179407Sobrien	 0x0000ffff,		/* src_mask */
386179407Sobrien	 0x0000ffff,		/* dst_mask */
387179407Sobrien	 FALSE),		/* pcrel_offset */
388179407Sobrien
389179407Sobrien  /* Offset from page pointer in the global offset table.  */
390179407Sobrien  HOWTO (R_MIPS_GOT_OFST,	/* type */
391179407Sobrien	 0,			/* rightshift */
392179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
393179407Sobrien	 16,			/* bitsize */
394179407Sobrien	 FALSE,			/* pc_relative */
395179407Sobrien	 0,			/* bitpos */
396179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
397179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
398179407Sobrien	 "R_MIPS_GOT_OFST",	/* name */
399179407Sobrien	 TRUE,			/* partial_inplace */
400179407Sobrien	 0x0000ffff,		/* src_mask */
401179407Sobrien	 0x0000ffff,		/* dst_mask */
402179407Sobrien	 FALSE),		/* pcrel_offset */
403179407Sobrien
404179407Sobrien  /* High 16 bits of displacement in global offset table.  */
405179407Sobrien  HOWTO (R_MIPS_GOT_HI16,	/* type */
406179407Sobrien	 0,			/* rightshift */
407179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
408179407Sobrien	 16,			/* bitsize */
409179407Sobrien	 FALSE,			/* pc_relative */
410179407Sobrien	 0,			/* bitpos */
411179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
412179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
413179407Sobrien	 "R_MIPS_GOT_HI16",	/* name */
414179407Sobrien	 TRUE,			/* partial_inplace */
415179407Sobrien	 0x0000ffff,		/* src_mask */
416179407Sobrien	 0x0000ffff,		/* dst_mask */
417179407Sobrien	 FALSE),		/* pcrel_offset */
418179407Sobrien
419179407Sobrien  /* Low 16 bits of displacement in global offset table.  */
420179407Sobrien  HOWTO (R_MIPS_GOT_LO16,	/* type */
421179407Sobrien	 0,			/* rightshift */
422179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
423179407Sobrien	 16,			/* bitsize */
424179407Sobrien	 FALSE,			/* pc_relative */
425179407Sobrien	 0,			/* bitpos */
426179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
427179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
428179407Sobrien	 "R_MIPS_GOT_LO16",	/* name */
429179407Sobrien	 TRUE,			/* partial_inplace */
430179407Sobrien	 0x0000ffff,		/* src_mask */
431179407Sobrien	 0x0000ffff,		/* dst_mask */
432179407Sobrien	 FALSE),		/* pcrel_offset */
433179407Sobrien
434179407Sobrien  /* 64 bit subtraction.  Used in the N32 ABI.  */
435179407Sobrien  HOWTO (R_MIPS_SUB,		/* type */
436179407Sobrien	 0,			/* rightshift */
437179407Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
438179407Sobrien	 64,			/* bitsize */
439179407Sobrien	 FALSE,			/* pc_relative */
440179407Sobrien	 0,			/* bitpos */
441179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
442179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
443179407Sobrien	 "R_MIPS_SUB",		/* name */
444179407Sobrien	 TRUE,			/* partial_inplace */
445179407Sobrien	 MINUS_ONE,		/* src_mask */
446179407Sobrien	 MINUS_ONE,		/* dst_mask */
447179407Sobrien	 FALSE),		/* pcrel_offset */
448179407Sobrien
449179407Sobrien  /* Used to cause the linker to insert and delete instructions?  */
450179407Sobrien  EMPTY_HOWTO (R_MIPS_INSERT_A),
451179407Sobrien  EMPTY_HOWTO (R_MIPS_INSERT_B),
452179407Sobrien  EMPTY_HOWTO (R_MIPS_DELETE),
453179407Sobrien
454179407Sobrien  /* Get the higher value of a 64 bit addend.  */
455179407Sobrien  HOWTO (R_MIPS_HIGHER,		/* type */
456179407Sobrien	 0,			/* rightshift */
457179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
458179407Sobrien	 16,			/* bitsize */
459179407Sobrien	 FALSE,			/* pc_relative */
460179407Sobrien	 0,			/* bitpos */
461179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
462179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
463179407Sobrien	 "R_MIPS_HIGHER",	/* name */
464179407Sobrien	 TRUE,			/* partial_inplace */
465179407Sobrien	 0x0000ffff,		/* src_mask */
466179407Sobrien	 0x0000ffff,		/* dst_mask */
467179407Sobrien	 FALSE),		/* pcrel_offset */
468179407Sobrien
469179407Sobrien  /* Get the highest value of a 64 bit addend.  */
470179407Sobrien  HOWTO (R_MIPS_HIGHEST,	/* type */
471179407Sobrien	 0,			/* rightshift */
472179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
473179407Sobrien	 16,			/* bitsize */
474179407Sobrien	 FALSE,			/* pc_relative */
475179407Sobrien	 0,			/* bitpos */
476179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
477179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
478179407Sobrien	 "R_MIPS_HIGHEST",	/* name */
479179407Sobrien	 TRUE,			/* partial_inplace */
480179407Sobrien	 0x0000ffff,		/* src_mask */
481179407Sobrien	 0x0000ffff,		/* dst_mask */
482179407Sobrien	 FALSE),		/* pcrel_offset */
483179407Sobrien
484179407Sobrien  /* High 16 bits of displacement in global offset table.  */
485179407Sobrien  HOWTO (R_MIPS_CALL_HI16,	/* type */
486179407Sobrien	 0,			/* rightshift */
487179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
488179407Sobrien	 16,			/* bitsize */
489179407Sobrien	 FALSE,			/* pc_relative */
490179407Sobrien	 0,			/* bitpos */
491179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
492179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
493179407Sobrien	 "R_MIPS_CALL_HI16",	/* name */
494179407Sobrien	 TRUE,			/* partial_inplace */
495179407Sobrien	 0x0000ffff,		/* src_mask */
496179407Sobrien	 0x0000ffff,		/* dst_mask */
497179407Sobrien	 FALSE),		/* pcrel_offset */
498179407Sobrien
499179407Sobrien  /* Low 16 bits of displacement in global offset table.  */
500179407Sobrien  HOWTO (R_MIPS_CALL_LO16,	/* type */
501179407Sobrien	 0,			/* rightshift */
502179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
503179407Sobrien	 16,			/* bitsize */
504179407Sobrien	 FALSE,			/* pc_relative */
505179407Sobrien	 0,			/* bitpos */
506179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
507179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
508179407Sobrien	 "R_MIPS_CALL_LO16",	/* name */
509179407Sobrien	 TRUE,			/* partial_inplace */
510179407Sobrien	 0x0000ffff,		/* src_mask */
511179407Sobrien	 0x0000ffff,		/* dst_mask */
512179407Sobrien	 FALSE),		/* pcrel_offset */
513179407Sobrien
514179407Sobrien  /* Section displacement.  */
515179407Sobrien  HOWTO (R_MIPS_SCN_DISP,       /* type */
516179407Sobrien	 0,			/* rightshift */
517179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
518179407Sobrien	 32,			/* bitsize */
519179407Sobrien	 FALSE,			/* pc_relative */
520179407Sobrien	 0,			/* bitpos */
521179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
522179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
523179407Sobrien	 "R_MIPS_SCN_DISP",     /* name */
524179407Sobrien	 TRUE,			/* partial_inplace */
525179407Sobrien	 0xffffffff,		/* src_mask */
526179407Sobrien	 0xffffffff,		/* dst_mask */
527179407Sobrien	 FALSE),		/* pcrel_offset */
528179407Sobrien
529179407Sobrien  EMPTY_HOWTO (R_MIPS_REL16),
530179407Sobrien  EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
531179407Sobrien  EMPTY_HOWTO (R_MIPS_PJUMP),
532179407Sobrien  EMPTY_HOWTO (R_MIPS_RELGOT),
533179407Sobrien
534179407Sobrien  /* Protected jump conversion.  This is an optimization hint.  No
535179407Sobrien     relocation is required for correctness.  */
536179407Sobrien  HOWTO (R_MIPS_JALR,	        /* type */
537179407Sobrien	 0,			/* rightshift */
538179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
539179407Sobrien	 32,			/* bitsize */
540179407Sobrien	 FALSE,			/* pc_relative */
541179407Sobrien	 0,			/* bitpos */
542179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
543179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
544179407Sobrien	 "R_MIPS_JALR",	        /* name */
545179407Sobrien	 FALSE,			/* partial_inplace */
546179407Sobrien	 0x00000000,		/* src_mask */
547179407Sobrien	 0x00000000,		/* dst_mask */
548179407Sobrien	 FALSE),		/* pcrel_offset */
549218822Sdim
550218822Sdim  /* TLS GD/LD dynamic relocations.  */
551218822Sdim  HOWTO (R_MIPS_TLS_DTPMOD32,	/* type */
552218822Sdim	 0,			/* rightshift */
553218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
554218822Sdim	 32,			/* bitsize */
555218822Sdim	 FALSE,			/* pc_relative */
556218822Sdim	 0,			/* bitpos */
557218822Sdim	 complain_overflow_dont, /* complain_on_overflow */
558218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
559218822Sdim	 "R_MIPS_TLS_DTPMOD32",	/* name */
560218822Sdim	 TRUE,			/* partial_inplace */
561218822Sdim	 0xffffffff,		/* src_mask */
562218822Sdim	 0xffffffff,		/* dst_mask */
563218822Sdim	 FALSE),		/* pcrel_offset */
564218822Sdim
565218822Sdim  HOWTO (R_MIPS_TLS_DTPREL32,	/* type */
566218822Sdim	 0,			/* rightshift */
567218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
568218822Sdim	 32,			/* bitsize */
569218822Sdim	 FALSE,			/* pc_relative */
570218822Sdim	 0,			/* bitpos */
571218822Sdim	 complain_overflow_dont, /* complain_on_overflow */
572218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
573218822Sdim	 "R_MIPS_TLS_DTPREL32",	/* name */
574218822Sdim	 TRUE,			/* partial_inplace */
575218822Sdim	 0xffffffff,		/* src_mask */
576218822Sdim	 0xffffffff,		/* dst_mask */
577218822Sdim	 FALSE),		/* pcrel_offset */
578218822Sdim
579218822Sdim  EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
580218822Sdim  EMPTY_HOWTO (R_MIPS_TLS_DTPREL64),
581218822Sdim
582218822Sdim  /* TLS general dynamic variable reference.  */
583218822Sdim  HOWTO (R_MIPS_TLS_GD,		/* type */
584218822Sdim	 0,			/* rightshift */
585218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
586218822Sdim	 16,			/* bitsize */
587218822Sdim	 FALSE,			/* pc_relative */
588218822Sdim	 0,			/* bitpos */
589218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
590218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
591218822Sdim	 "R_MIPS_TLS_GD",	/* name */
592218822Sdim	 TRUE,			/* partial_inplace */
593218822Sdim	 0x0000ffff,		/* src_mask */
594218822Sdim	 0x0000ffff,		/* dst_mask */
595218822Sdim	 FALSE),		/* pcrel_offset */
596218822Sdim
597218822Sdim  /* TLS local dynamic variable reference.  */
598218822Sdim  HOWTO (R_MIPS_TLS_LDM,	/* type */
599218822Sdim	 0,			/* rightshift */
600218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
601218822Sdim	 16,			/* bitsize */
602218822Sdim	 FALSE,			/* pc_relative */
603218822Sdim	 0,			/* bitpos */
604218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
605218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
606218822Sdim	 "R_MIPS_TLS_LDM",	/* name */
607218822Sdim	 TRUE,			/* partial_inplace */
608218822Sdim	 0x0000ffff,		/* src_mask */
609218822Sdim	 0x0000ffff,		/* dst_mask */
610218822Sdim	 FALSE),		/* pcrel_offset */
611218822Sdim
612218822Sdim  /* TLS local dynamic offset.  */
613218822Sdim  HOWTO (R_MIPS_TLS_DTPREL_HI16,	/* type */
614218822Sdim	 0,			/* rightshift */
615218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
616218822Sdim	 16,			/* bitsize */
617218822Sdim	 FALSE,			/* pc_relative */
618218822Sdim	 0,			/* bitpos */
619218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
620218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
621218822Sdim	 "R_MIPS_TLS_DTPREL_HI16",	/* name */
622218822Sdim	 TRUE,			/* partial_inplace */
623218822Sdim	 0x0000ffff,		/* src_mask */
624218822Sdim	 0x0000ffff,		/* dst_mask */
625218822Sdim	 FALSE),		/* pcrel_offset */
626218822Sdim
627218822Sdim  /* TLS local dynamic offset.  */
628218822Sdim  HOWTO (R_MIPS_TLS_DTPREL_LO16,	/* type */
629218822Sdim	 0,			/* rightshift */
630218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
631218822Sdim	 16,			/* bitsize */
632218822Sdim	 FALSE,			/* pc_relative */
633218822Sdim	 0,			/* bitpos */
634218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
635218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
636218822Sdim	 "R_MIPS_TLS_DTPREL_LO16",	/* name */
637218822Sdim	 TRUE,			/* partial_inplace */
638218822Sdim	 0x0000ffff,		/* src_mask */
639218822Sdim	 0x0000ffff,		/* dst_mask */
640218822Sdim	 FALSE),		/* pcrel_offset */
641218822Sdim
642218822Sdim  /* TLS thread pointer offset.  */
643218822Sdim  HOWTO (R_MIPS_TLS_GOTTPREL,	/* type */
644218822Sdim	 0,			/* rightshift */
645218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
646218822Sdim	 16,			/* bitsize */
647218822Sdim	 FALSE,			/* pc_relative */
648218822Sdim	 0,			/* bitpos */
649218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
650218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
651218822Sdim	 "R_MIPS_TLS_GOTTPREL",	/* name */
652218822Sdim	 TRUE,			/* partial_inplace */
653218822Sdim	 0x0000ffff,		/* src_mask */
654218822Sdim	 0x0000ffff,		/* dst_mask */
655218822Sdim	 FALSE),		/* pcrel_offset */
656218822Sdim
657218822Sdim  /* TLS IE dynamic relocations.  */
658218822Sdim  HOWTO (R_MIPS_TLS_TPREL32,	/* type */
659218822Sdim	 0,			/* rightshift */
660218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
661218822Sdim	 32,			/* bitsize */
662218822Sdim	 FALSE,			/* pc_relative */
663218822Sdim	 0,			/* bitpos */
664218822Sdim	 complain_overflow_dont, /* complain_on_overflow */
665218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
666218822Sdim	 "R_MIPS_TLS_TPREL32",	/* name */
667218822Sdim	 TRUE,			/* partial_inplace */
668218822Sdim	 0xffffffff,		/* src_mask */
669218822Sdim	 0xffffffff,		/* dst_mask */
670218822Sdim	 FALSE),		/* pcrel_offset */
671218822Sdim
672218822Sdim  EMPTY_HOWTO (R_MIPS_TLS_TPREL64),
673218822Sdim
674218822Sdim  /* TLS thread pointer offset.  */
675218822Sdim  HOWTO (R_MIPS_TLS_TPREL_HI16,	/* type */
676218822Sdim	 0,			/* rightshift */
677218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
678218822Sdim	 16,			/* bitsize */
679218822Sdim	 FALSE,			/* pc_relative */
680218822Sdim	 0,			/* bitpos */
681218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
682218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
683218822Sdim	 "R_MIPS_TLS_TPREL_HI16", /* name */
684218822Sdim	 TRUE,			/* partial_inplace */
685218822Sdim	 0x0000ffff,		/* src_mask */
686218822Sdim	 0x0000ffff,		/* dst_mask */
687218822Sdim	 FALSE),		/* pcrel_offset */
688218822Sdim
689218822Sdim  /* TLS thread pointer offset.  */
690218822Sdim  HOWTO (R_MIPS_TLS_TPREL_LO16,	/* type */
691218822Sdim	 0,			/* rightshift */
692218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
693218822Sdim	 16,			/* bitsize */
694218822Sdim	 FALSE,			/* pc_relative */
695218822Sdim	 0,			/* bitpos */
696218822Sdim	 complain_overflow_signed, /* complain_on_overflow */
697218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
698218822Sdim	 "R_MIPS_TLS_TPREL_LO16", /* name */
699218822Sdim	 TRUE,			/* partial_inplace */
700218822Sdim	 0x0000ffff,		/* src_mask */
701218822Sdim	 0x0000ffff,		/* dst_mask */
702218822Sdim	 FALSE),		/* pcrel_offset */
703218822Sdim
704218822Sdim  /* 32 bit relocation with no addend.  */
705218822Sdim  HOWTO (R_MIPS_GLOB_DAT,	/* type */
706218822Sdim	 0,			/* rightshift */
707218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
708218822Sdim	 32,			/* bitsize */
709218822Sdim	 FALSE,			/* pc_relative */
710218822Sdim	 0,			/* bitpos */
711218822Sdim	 complain_overflow_dont, /* complain_on_overflow */
712218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
713218822Sdim	 "R_MIPS_GLOB_DAT",	/* name */
714218822Sdim	 FALSE,			/* partial_inplace */
715218822Sdim	 0x0,			/* src_mask */
716218822Sdim	 0xffffffff,		/* dst_mask */
717218822Sdim	 FALSE),		/* pcrel_offset */
718179407Sobrien};
719179407Sobrien
720179407Sobrien/* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link.  This
721179407Sobrien   is a hack to make the linker think that we need 64 bit values.  */
722179407Sobrienstatic reloc_howto_type elf_mips_ctor64_howto =
723179407Sobrien  HOWTO (R_MIPS_64,		/* type */
724179407Sobrien	 0,			/* rightshift */
725179407Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
726179407Sobrien	 32,			/* bitsize */
727179407Sobrien	 FALSE,			/* pc_relative */
728179407Sobrien	 0,			/* bitpos */
729179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
730179407Sobrien	 mips32_64bit_reloc,	/* special_function */
731179407Sobrien	 "R_MIPS_64",		/* name */
732179407Sobrien	 TRUE,			/* partial_inplace */
733179407Sobrien	 0xffffffff,		/* src_mask */
734179407Sobrien	 0xffffffff,		/* dst_mask */
735179407Sobrien	 FALSE);		/* pcrel_offset */
736179407Sobrien
737218822Sdimstatic reloc_howto_type elf_mips16_howto_table_rel[] =
738218822Sdim{
739218822Sdim  /* The reloc used for the mips16 jump instruction.  */
740179407Sobrien  HOWTO (R_MIPS16_26,		/* type */
741179407Sobrien	 2,			/* rightshift */
742179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
743179407Sobrien	 26,			/* bitsize */
744179407Sobrien	 FALSE,			/* pc_relative */
745179407Sobrien	 0,			/* bitpos */
746179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
747179407Sobrien	 			/* This needs complex overflow
748179407Sobrien				   detection, because the upper four
749179407Sobrien				   bits must match the PC.  */
750218822Sdim	 _bfd_mips_elf_generic_reloc, /* special_function */
751179407Sobrien	 "R_MIPS16_26",		/* name */
752179407Sobrien	 TRUE,			/* partial_inplace */
753179407Sobrien	 0x3ffffff,		/* src_mask */
754179407Sobrien	 0x3ffffff,		/* dst_mask */
755218822Sdim	 FALSE),		/* pcrel_offset */
756179407Sobrien
757218822Sdim  /* The reloc used for the mips16 gprel instruction.  */
758179407Sobrien  HOWTO (R_MIPS16_GPREL,	/* type */
759179407Sobrien	 0,			/* rightshift */
760179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
761179407Sobrien	 16,			/* bitsize */
762179407Sobrien	 FALSE,			/* pc_relative */
763179407Sobrien	 0,			/* bitpos */
764179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
765179407Sobrien	 mips16_gprel_reloc,	/* special_function */
766179407Sobrien	 "R_MIPS16_GPREL",	/* name */
767179407Sobrien	 TRUE,			/* partial_inplace */
768218822Sdim	 0x0000ffff,		/* src_mask */
769218822Sdim	 0x0000ffff,	        /* dst_mask */
770218822Sdim	 FALSE),		/* pcrel_offset */
771179407Sobrien
772218822Sdim  /* A placeholder for MIPS16 reference to global offset table.  */
773218822Sdim  EMPTY_HOWTO (R_MIPS16_GOT16),
774218822Sdim
775218822Sdim  /* A placeholder for MIPS16 16 bit call through global offset table.  */
776218822Sdim  EMPTY_HOWTO (R_MIPS16_CALL16),
777218822Sdim
778218822Sdim  /* MIPS16 high 16 bits of symbol value.  */
779218822Sdim  HOWTO (R_MIPS16_HI16,		/* type */
780179407Sobrien	 16,			/* rightshift */
781179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
782179407Sobrien	 16,			/* bitsize */
783218822Sdim	 FALSE,			/* pc_relative */
784179407Sobrien	 0,			/* bitpos */
785179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
786179407Sobrien	 _bfd_mips_elf_hi16_reloc, /* special_function */
787218822Sdim	 "R_MIPS16_HI16",	/* name */
788179407Sobrien	 TRUE,			/* partial_inplace */
789218822Sdim	 0x0000ffff,		/* src_mask */
790218822Sdim	 0x0000ffff,	        /* dst_mask */
791218822Sdim	 FALSE),		/* pcrel_offset */
792179407Sobrien
793218822Sdim  /* MIPS16 low 16 bits of symbol value.  */
794218822Sdim  HOWTO (R_MIPS16_LO16,		/* type */
795179407Sobrien	 0,			/* rightshift */
796179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
797179407Sobrien	 16,			/* bitsize */
798218822Sdim	 FALSE,			/* pc_relative */
799179407Sobrien	 0,			/* bitpos */
800179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
801179407Sobrien	 _bfd_mips_elf_lo16_reloc, /* special_function */
802218822Sdim	 "R_MIPS16_LO16",	/* name */
803179407Sobrien	 TRUE,			/* partial_inplace */
804218822Sdim	 0x0000ffff,		/* src_mask */
805218822Sdim	 0x0000ffff,	        /* dst_mask */
806218822Sdim	 FALSE),		/* pcrel_offset */
807218822Sdim};
808179407Sobrien
809179407Sobrien/* 16 bit offset for pc-relative branches.  */
810179407Sobrienstatic reloc_howto_type elf_mips_gnu_rel16_s2 =
811179407Sobrien  HOWTO (R_MIPS_GNU_REL16_S2,	/* type */
812179407Sobrien	 2,			/* rightshift */
813179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
814179407Sobrien	 16,			/* bitsize */
815179407Sobrien	 TRUE,			/* pc_relative */
816179407Sobrien	 0,			/* bitpos */
817179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
818179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
819179407Sobrien	 "R_MIPS_GNU_REL16_S2",	/* name */
820179407Sobrien	 TRUE,			/* partial_inplace */
821179407Sobrien	 0xffff,		/* src_mask */
822179407Sobrien	 0xffff,		/* dst_mask */
823179407Sobrien	 TRUE);			/* pcrel_offset */
824179407Sobrien
825218822Sdim/* 32 bit pc-relative.  This was a GNU extension used by embedded-PIC.
826218822Sdim   It was co-opted by mips-linux for exception-handling data.  It is no
827218822Sdim   longer used, but should continue to be supported by the linker for
828218822Sdim   backward compatibility.  (GCC stopped using it in May, 2004.)  */
829179407Sobrienstatic reloc_howto_type elf_mips_gnu_pcrel32 =
830179407Sobrien  HOWTO (R_MIPS_PC32,		/* type */
831179407Sobrien	 0,			/* rightshift */
832179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
833179407Sobrien	 32,			/* bitsize */
834179407Sobrien	 TRUE,			/* pc_relative */
835179407Sobrien	 0,			/* bitpos */
836179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
837179407Sobrien	 _bfd_mips_elf_generic_reloc, /* special_function */
838179407Sobrien	 "R_MIPS_PC32",		/* name */
839179407Sobrien	 TRUE,			/* partial_inplace */
840179407Sobrien	 0xffffffff,		/* src_mask */
841179407Sobrien	 0xffffffff,		/* dst_mask */
842179407Sobrien	 TRUE);			/* pcrel_offset */
843179407Sobrien
844179407Sobrien/* GNU extension to record C++ vtable hierarchy */
845179407Sobrienstatic reloc_howto_type elf_mips_gnu_vtinherit_howto =
846179407Sobrien  HOWTO (R_MIPS_GNU_VTINHERIT,	/* type */
847179407Sobrien	 0,			/* rightshift */
848179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
849179407Sobrien	 0,			/* bitsize */
850179407Sobrien	 FALSE,			/* pc_relative */
851179407Sobrien	 0,			/* bitpos */
852179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
853179407Sobrien	 NULL,			/* special_function */
854179407Sobrien	 "R_MIPS_GNU_VTINHERIT", /* name */
855179407Sobrien	 FALSE,			/* partial_inplace */
856179407Sobrien	 0,			/* src_mask */
857179407Sobrien	 0,			/* dst_mask */
858179407Sobrien	 FALSE);		/* pcrel_offset */
859179407Sobrien
860179407Sobrien/* GNU extension to record C++ vtable member usage */
861179407Sobrienstatic reloc_howto_type elf_mips_gnu_vtentry_howto =
862179407Sobrien  HOWTO (R_MIPS_GNU_VTENTRY,	/* type */
863179407Sobrien	 0,			/* rightshift */
864179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
865179407Sobrien	 0,			/* bitsize */
866179407Sobrien	 FALSE,			/* pc_relative */
867179407Sobrien	 0,			/* bitpos */
868179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
869179407Sobrien	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
870179407Sobrien	 "R_MIPS_GNU_VTENTRY",	/* name */
871179407Sobrien	 FALSE,			/* partial_inplace */
872179407Sobrien	 0,			/* src_mask */
873179407Sobrien	 0,			/* dst_mask */
874179407Sobrien	 FALSE);		/* pcrel_offset */
875179407Sobrien
876179407Sobrien/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
877179407Sobrien   dangerous relocation.  */
878179407Sobrien
879179407Sobrienstatic bfd_boolean
880179407Sobrienmips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
881179407Sobrien{
882179407Sobrien  unsigned int count;
883179407Sobrien  asymbol **sym;
884179407Sobrien  unsigned int i;
885179407Sobrien
886179407Sobrien  /* If we've already figured out what GP will be, just return it.  */
887179407Sobrien  *pgp = _bfd_get_gp_value (output_bfd);
888179407Sobrien  if (*pgp)
889179407Sobrien    return TRUE;
890179407Sobrien
891179407Sobrien  count = bfd_get_symcount (output_bfd);
892179407Sobrien  sym = bfd_get_outsymbols (output_bfd);
893179407Sobrien
894179407Sobrien  /* The linker script will have created a symbol named `_gp' with the
895179407Sobrien     appropriate value.  */
896179407Sobrien  if (sym == NULL)
897179407Sobrien    i = count;
898179407Sobrien  else
899179407Sobrien    {
900179407Sobrien      for (i = 0; i < count; i++, sym++)
901179407Sobrien	{
902179407Sobrien	  register const char *name;
903179407Sobrien
904179407Sobrien	  name = bfd_asymbol_name (*sym);
905179407Sobrien	  if (*name == '_' && strcmp (name, "_gp") == 0)
906179407Sobrien	    {
907179407Sobrien	      *pgp = bfd_asymbol_value (*sym);
908179407Sobrien	      _bfd_set_gp_value (output_bfd, *pgp);
909179407Sobrien	      break;
910179407Sobrien	    }
911179407Sobrien	}
912179407Sobrien    }
913179407Sobrien
914179407Sobrien  if (i >= count)
915179407Sobrien    {
916179407Sobrien      /* Only get the error once.  */
917179407Sobrien      *pgp = 4;
918179407Sobrien      _bfd_set_gp_value (output_bfd, *pgp);
919179407Sobrien      return FALSE;
920179407Sobrien    }
921179407Sobrien
922179407Sobrien  return TRUE;
923179407Sobrien}
924179407Sobrien
925179407Sobrien/* We have to figure out the gp value, so that we can adjust the
926179407Sobrien   symbol value correctly.  We look up the symbol _gp in the output
927179407Sobrien   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
928179407Sobrien   target data.  We don't need to adjust the symbol value for an
929179407Sobrien   external symbol if we are producing relocatable output.  */
930179407Sobrien
931179407Sobrienstatic bfd_reloc_status_type
932179407Sobrienmips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
933179407Sobrien		   char **error_message, bfd_vma *pgp)
934179407Sobrien{
935179407Sobrien  if (bfd_is_und_section (symbol->section)
936179407Sobrien      && ! relocatable)
937179407Sobrien    {
938179407Sobrien      *pgp = 0;
939179407Sobrien      return bfd_reloc_undefined;
940179407Sobrien    }
941179407Sobrien
942179407Sobrien  *pgp = _bfd_get_gp_value (output_bfd);
943179407Sobrien  if (*pgp == 0
944179407Sobrien      && (! relocatable
945179407Sobrien	  || (symbol->flags & BSF_SECTION_SYM) != 0))
946179407Sobrien    {
947179407Sobrien      if (relocatable)
948179407Sobrien	{
949179407Sobrien	  /* Make up a value.  */
950179407Sobrien	  *pgp = symbol->section->output_section->vma + 0x4000;
951179407Sobrien	  _bfd_set_gp_value (output_bfd, *pgp);
952179407Sobrien	}
953179407Sobrien      else if (!mips_elf_assign_gp (output_bfd, pgp))
954179407Sobrien	{
955179407Sobrien	  *error_message =
956179407Sobrien	    (char *) _("GP relative relocation when _gp not defined");
957179407Sobrien	  return bfd_reloc_dangerous;
958179407Sobrien	}
959179407Sobrien    }
960179407Sobrien
961179407Sobrien  return bfd_reloc_ok;
962179407Sobrien}
963179407Sobrien
964179407Sobrien/* Do a R_MIPS_GPREL16 relocation.  This is a 16 bit value which must
965179407Sobrien   become the offset from the gp register.  This function also handles
966179407Sobrien   R_MIPS_LITERAL relocations, although those can be handled more
967179407Sobrien   cleverly because the entries in the .lit8 and .lit4 sections can be
968179407Sobrien   merged.  */
969179407Sobrien
970179407Sobrienbfd_reloc_status_type
971179407Sobrien_bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry,
972179407Sobrien			       asymbol *symbol, void *data,
973179407Sobrien			       asection *input_section, bfd *output_bfd,
974179407Sobrien			       char **error_message)
975179407Sobrien{
976179407Sobrien  bfd_boolean relocatable;
977179407Sobrien  bfd_reloc_status_type ret;
978179407Sobrien  bfd_vma gp;
979179407Sobrien
980218822Sdim  /* R_MIPS_LITERAL relocations are defined for local symbols only.  */
981218822Sdim  if (reloc_entry->howto->type == R_MIPS_LITERAL
982218822Sdim      && output_bfd != NULL
983218822Sdim      && (symbol->flags & BSF_SECTION_SYM) == 0
984218822Sdim      && (symbol->flags & BSF_LOCAL) != 0)
985218822Sdim    {
986218822Sdim      *error_message = (char *)
987218822Sdim	_("literal relocation occurs for an external symbol");
988218822Sdim      return bfd_reloc_outofrange;
989218822Sdim    }
990218822Sdim
991179407Sobrien  if (output_bfd != NULL)
992179407Sobrien    relocatable = TRUE;
993179407Sobrien  else
994179407Sobrien    {
995179407Sobrien      relocatable = FALSE;
996179407Sobrien      output_bfd = symbol->section->output_section->owner;
997179407Sobrien    }
998179407Sobrien
999179407Sobrien  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
1000179407Sobrien			   &gp);
1001179407Sobrien  if (ret != bfd_reloc_ok)
1002179407Sobrien    return ret;
1003179407Sobrien
1004179407Sobrien  return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
1005179407Sobrien					input_section, relocatable,
1006179407Sobrien					data, gp);
1007179407Sobrien}
1008179407Sobrien
1009179407Sobrien/* Do a R_MIPS_GPREL32 relocation.  This is a 32 bit value which must
1010179407Sobrien   become the offset from the gp register.  */
1011179407Sobrien
1012179407Sobrienstatic bfd_reloc_status_type
1013179407Sobrienmips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1014179407Sobrien			void *data, asection *input_section, bfd *output_bfd,
1015179407Sobrien			char **error_message)
1016179407Sobrien{
1017179407Sobrien  bfd_boolean relocatable;
1018179407Sobrien  bfd_reloc_status_type ret;
1019179407Sobrien  bfd_vma gp;
1020179407Sobrien
1021218822Sdim  /* R_MIPS_GPREL32 relocations are defined for local symbols only.  */
1022218822Sdim  if (output_bfd != NULL
1023218822Sdim      && (symbol->flags & BSF_SECTION_SYM) == 0
1024218822Sdim      && (symbol->flags & BSF_LOCAL) != 0)
1025218822Sdim    {
1026218822Sdim      *error_message = (char *)
1027218822Sdim	_("32bits gp relative relocation occurs for an external symbol");
1028218822Sdim      return bfd_reloc_outofrange;
1029218822Sdim    }
1030218822Sdim
1031179407Sobrien  if (output_bfd != NULL)
1032179407Sobrien    relocatable = TRUE;
1033179407Sobrien  else
1034179407Sobrien    {
1035179407Sobrien      relocatable = FALSE;
1036179407Sobrien      output_bfd = symbol->section->output_section->owner;
1037179407Sobrien    }
1038179407Sobrien
1039179407Sobrien  ret = mips_elf_final_gp (output_bfd, symbol, relocatable,
1040179407Sobrien			   error_message, &gp);
1041179407Sobrien  if (ret != bfd_reloc_ok)
1042179407Sobrien    return ret;
1043179407Sobrien
1044179407Sobrien  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
1045179407Sobrien			  relocatable, data, gp);
1046179407Sobrien}
1047179407Sobrien
1048179407Sobrienstatic bfd_reloc_status_type
1049179407Sobriengprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
1050179407Sobrien		 asection *input_section, bfd_boolean relocatable,
1051179407Sobrien		 void *data, bfd_vma gp)
1052179407Sobrien{
1053179407Sobrien  bfd_vma relocation;
1054179407Sobrien  bfd_vma val;
1055179407Sobrien
1056179407Sobrien  if (bfd_is_com_section (symbol->section))
1057179407Sobrien    relocation = 0;
1058179407Sobrien  else
1059179407Sobrien    relocation = symbol->value;
1060179407Sobrien
1061179407Sobrien  relocation += symbol->section->output_section->vma;
1062179407Sobrien  relocation += symbol->section->output_offset;
1063179407Sobrien
1064218822Sdim  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
1065179407Sobrien    return bfd_reloc_outofrange;
1066179407Sobrien
1067179407Sobrien  /* Set val to the offset into the section or symbol.  */
1068179407Sobrien  val = reloc_entry->addend;
1069179407Sobrien
1070179407Sobrien  if (reloc_entry->howto->partial_inplace)
1071179407Sobrien    val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
1072179407Sobrien
1073179407Sobrien  /* Adjust val for the final section location and GP value.  If we
1074179407Sobrien     are producing relocatable output, we don't want to do this for
1075179407Sobrien     an external symbol.  */
1076179407Sobrien  if (! relocatable
1077179407Sobrien      || (symbol->flags & BSF_SECTION_SYM) != 0)
1078179407Sobrien    val += relocation - gp;
1079179407Sobrien
1080179407Sobrien  if (reloc_entry->howto->partial_inplace)
1081179407Sobrien    bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
1082179407Sobrien  else
1083179407Sobrien    reloc_entry->addend = val;
1084179407Sobrien
1085179407Sobrien  if (relocatable)
1086179407Sobrien    reloc_entry->address += input_section->output_offset;
1087179407Sobrien
1088179407Sobrien  return bfd_reloc_ok;
1089179407Sobrien}
1090179407Sobrien
1091179407Sobrien/* Handle a 64 bit reloc in a 32 bit MIPS ELF file.  These are
1092179407Sobrien   generated when addresses are 64 bits.  The upper 32 bits are a simple
1093179407Sobrien   sign extension.  */
1094179407Sobrien
1095179407Sobrienstatic bfd_reloc_status_type
1096179407Sobrienmips32_64bit_reloc (bfd *abfd, arelent *reloc_entry,
1097179407Sobrien		    asymbol *symbol ATTRIBUTE_UNUSED,
1098179407Sobrien		    void *data, asection *input_section,
1099179407Sobrien		    bfd *output_bfd, char **error_message)
1100179407Sobrien{
1101179407Sobrien  bfd_reloc_status_type r;
1102179407Sobrien  arelent reloc32;
1103179407Sobrien  unsigned long val;
1104179407Sobrien  bfd_size_type addr;
1105179407Sobrien
1106179407Sobrien  /* Do a normal 32 bit relocation on the lower 32 bits.  */
1107179407Sobrien  reloc32 = *reloc_entry;
1108179407Sobrien  if (bfd_big_endian (abfd))
1109179407Sobrien    reloc32.address += 4;
1110179407Sobrien  reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32];
1111179407Sobrien  r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
1112179407Sobrien			      output_bfd, error_message);
1113179407Sobrien
1114179407Sobrien  /* Sign extend into the upper 32 bits.  */
1115179407Sobrien  val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address);
1116179407Sobrien  if ((val & 0x80000000) != 0)
1117179407Sobrien    val = 0xffffffff;
1118179407Sobrien  else
1119179407Sobrien    val = 0;
1120179407Sobrien  addr = reloc_entry->address;
1121179407Sobrien  if (bfd_little_endian (abfd))
1122179407Sobrien    addr += 4;
1123179407Sobrien  bfd_put_32 (abfd, val, (bfd_byte *) data + addr);
1124179407Sobrien
1125179407Sobrien  return r;
1126179407Sobrien}
1127179407Sobrien
1128179407Sobrien/* Handle a mips16 GP relative reloc.  */
1129179407Sobrien
1130179407Sobrienstatic bfd_reloc_status_type
1131179407Sobrienmips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
1132179407Sobrien		    void *data, asection *input_section, bfd *output_bfd,
1133179407Sobrien		    char **error_message)
1134179407Sobrien{
1135179407Sobrien  bfd_boolean relocatable;
1136179407Sobrien  bfd_reloc_status_type ret;
1137218822Sdim  bfd_byte *location;
1138179407Sobrien  bfd_vma gp;
1139179407Sobrien
1140179407Sobrien  /* If we're relocating, and this is an external symbol, we don't want
1141179407Sobrien     to change anything.  */
1142179407Sobrien  if (output_bfd != NULL
1143179407Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0
1144179407Sobrien      && (symbol->flags & BSF_LOCAL) != 0)
1145179407Sobrien    {
1146179407Sobrien      reloc_entry->address += input_section->output_offset;
1147179407Sobrien      return bfd_reloc_ok;
1148179407Sobrien    }
1149179407Sobrien
1150179407Sobrien  if (output_bfd != NULL)
1151179407Sobrien    relocatable = TRUE;
1152179407Sobrien  else
1153179407Sobrien    {
1154179407Sobrien      relocatable = FALSE;
1155179407Sobrien      output_bfd = symbol->section->output_section->owner;
1156179407Sobrien    }
1157179407Sobrien
1158179407Sobrien  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
1159179407Sobrien			   &gp);
1160179407Sobrien  if (ret != bfd_reloc_ok)
1161179407Sobrien    return ret;
1162179407Sobrien
1163218822Sdim  location = (bfd_byte *) data + reloc_entry->address;
1164218822Sdim  _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
1165218822Sdim				   location);
1166218822Sdim  ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
1167218822Sdim				       input_section, relocatable,
1168218822Sdim				       data, gp);
1169218822Sdim  _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable,
1170218822Sdim				 location);
1171179407Sobrien
1172218822Sdim  return ret;
1173179407Sobrien}
1174179407Sobrien
1175179407Sobrien/* A mapping from BFD reloc types to MIPS ELF reloc types.  */
1176179407Sobrien
1177179407Sobrienstruct elf_reloc_map {
1178179407Sobrien  bfd_reloc_code_real_type bfd_val;
1179179407Sobrien  enum elf_mips_reloc_type elf_val;
1180179407Sobrien};
1181179407Sobrien
1182179407Sobrienstatic const struct elf_reloc_map mips_reloc_map[] =
1183179407Sobrien{
1184179407Sobrien  { BFD_RELOC_NONE, R_MIPS_NONE },
1185179407Sobrien  { BFD_RELOC_16, R_MIPS_16 },
1186179407Sobrien  { BFD_RELOC_32, R_MIPS_32 },
1187179407Sobrien  /* There is no BFD reloc for R_MIPS_REL32.  */
1188179407Sobrien  { BFD_RELOC_64, R_MIPS_64 },
1189179407Sobrien  { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
1190179407Sobrien  { BFD_RELOC_HI16_S, R_MIPS_HI16 },
1191179407Sobrien  { BFD_RELOC_LO16, R_MIPS_LO16 },
1192179407Sobrien  { BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
1193179407Sobrien  { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
1194179407Sobrien  { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
1195218822Sdim  { BFD_RELOC_16_PCREL_S2, R_MIPS_PC16 },
1196179407Sobrien  { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
1197179407Sobrien  { BFD_RELOC_GPREL32, R_MIPS_GPREL32 },
1198179407Sobrien  { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
1199179407Sobrien  { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
1200179407Sobrien  { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
1201179407Sobrien  { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 },
1202179407Sobrien  { BFD_RELOC_MIPS_SUB, R_MIPS_SUB },
1203179407Sobrien  { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE },
1204179407Sobrien  { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST },
1205218822Sdim  { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP },
1206218822Sdim  { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 },
1207218822Sdim  { BFD_RELOC_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL32 },
1208218822Sdim  { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 },
1209218822Sdim  { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 },
1210218822Sdim  { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD },
1211218822Sdim  { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM },
1212218822Sdim  { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 },
1213218822Sdim  { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 },
1214218822Sdim  { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL },
1215218822Sdim  { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 },
1216218822Sdim  { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 },
1217218822Sdim  { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 },
1218218822Sdim  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }
1219179407Sobrien};
1220179407Sobrien
1221218822Sdimstatic const struct elf_reloc_map mips16_reloc_map[] =
1222218822Sdim{
1223218822Sdim  { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
1224218822Sdim  { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
1225218822Sdim  { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
1226218822Sdim  { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
1227218822Sdim};
1228218822Sdim
1229179407Sobrien/* Given a BFD reloc type, return a howto structure.  */
1230179407Sobrien
1231179407Sobrienstatic reloc_howto_type *
1232179407Sobrienbfd_elf32_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
1233179407Sobrien{
1234179407Sobrien  unsigned int i;
1235179407Sobrien  reloc_howto_type *howto_table = elf_mips_howto_table_rel;
1236218822Sdim  reloc_howto_type *howto16_table = elf_mips16_howto_table_rel;
1237179407Sobrien
1238179407Sobrien  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
1239179407Sobrien       i++)
1240179407Sobrien    {
1241179407Sobrien      if (mips_reloc_map[i].bfd_val == code)
1242179407Sobrien	return &howto_table[(int) mips_reloc_map[i].elf_val];
1243179407Sobrien    }
1244179407Sobrien
1245218822Sdim  for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
1246218822Sdim       i++)
1247218822Sdim    {
1248218822Sdim      if (mips16_reloc_map[i].bfd_val == code)
1249218822Sdim	return &howto16_table[(int) mips16_reloc_map[i].elf_val];
1250218822Sdim    }
1251218822Sdim
1252179407Sobrien  switch (code)
1253179407Sobrien    {
1254179407Sobrien    default:
1255179407Sobrien      bfd_set_error (bfd_error_bad_value);
1256179407Sobrien      return NULL;
1257179407Sobrien
1258179407Sobrien    case BFD_RELOC_CTOR:
1259179407Sobrien      /* We need to handle BFD_RELOC_CTOR specially.
1260179407Sobrien	 Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
1261179407Sobrien	 size of addresses of the ABI.  */
1262179407Sobrien      if ((elf_elfheader (abfd)->e_flags & (E_MIPS_ABI_O64
1263179407Sobrien					    | E_MIPS_ABI_EABI64)) != 0)
1264179407Sobrien	return &elf_mips_ctor64_howto;
1265179407Sobrien      else
1266179407Sobrien	return &howto_table[(int) R_MIPS_32];
1267179407Sobrien
1268179407Sobrien    case BFD_RELOC_VTABLE_INHERIT:
1269179407Sobrien      return &elf_mips_gnu_vtinherit_howto;
1270179407Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1271179407Sobrien      return &elf_mips_gnu_vtentry_howto;
1272179407Sobrien    case BFD_RELOC_32_PCREL:
1273179407Sobrien      return &elf_mips_gnu_pcrel32;
1274179407Sobrien    }
1275179407Sobrien}
1276179407Sobrien
1277218822Sdimstatic reloc_howto_type *
1278218822Sdimbfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1279218822Sdim				 const char *r_name)
1280218822Sdim{
1281218822Sdim  unsigned int i;
1282218822Sdim
1283218822Sdim  for (i = 0;
1284218822Sdim       i < (sizeof (elf_mips_howto_table_rel)
1285218822Sdim	    / sizeof (elf_mips_howto_table_rel[0]));
1286218822Sdim       i++)
1287218822Sdim    if (elf_mips_howto_table_rel[i].name != NULL
1288218822Sdim	&& strcasecmp (elf_mips_howto_table_rel[i].name, r_name) == 0)
1289218822Sdim      return &elf_mips_howto_table_rel[i];
1290218822Sdim
1291218822Sdim  for (i = 0;
1292218822Sdim       i < (sizeof (elf_mips16_howto_table_rel)
1293218822Sdim	    / sizeof (elf_mips16_howto_table_rel[0]));
1294218822Sdim       i++)
1295218822Sdim    if (elf_mips16_howto_table_rel[i].name != NULL
1296218822Sdim	&& strcasecmp (elf_mips16_howto_table_rel[i].name, r_name) == 0)
1297218822Sdim      return &elf_mips16_howto_table_rel[i];
1298218822Sdim
1299218822Sdim  if (strcasecmp (elf_mips_gnu_pcrel32.name, r_name) == 0)
1300218822Sdim    return &elf_mips_gnu_pcrel32;
1301218822Sdim  if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0)
1302218822Sdim    return &elf_mips_gnu_rel16_s2;
1303218822Sdim  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
1304218822Sdim    return &elf_mips_gnu_vtinherit_howto;
1305218822Sdim  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0)
1306218822Sdim    return &elf_mips_gnu_vtentry_howto;
1307218822Sdim
1308218822Sdim  return NULL;
1309218822Sdim}
1310218822Sdim
1311179407Sobrien/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
1312179407Sobrien
1313179407Sobrienstatic reloc_howto_type *
1314179407Sobrienmips_elf32_rtype_to_howto (unsigned int r_type,
1315179407Sobrien			   bfd_boolean rela_p ATTRIBUTE_UNUSED)
1316179407Sobrien{
1317179407Sobrien  switch (r_type)
1318179407Sobrien    {
1319179407Sobrien    case R_MIPS_GNU_VTINHERIT:
1320179407Sobrien      return &elf_mips_gnu_vtinherit_howto;
1321179407Sobrien    case R_MIPS_GNU_VTENTRY:
1322179407Sobrien      return &elf_mips_gnu_vtentry_howto;
1323179407Sobrien    case R_MIPS_GNU_REL16_S2:
1324179407Sobrien      return &elf_mips_gnu_rel16_s2;
1325179407Sobrien    case R_MIPS_PC32:
1326179407Sobrien      return &elf_mips_gnu_pcrel32;
1327179407Sobrien    default:
1328218822Sdim      if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
1329218822Sdim        return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min];
1330179407Sobrien      BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
1331179407Sobrien      return &elf_mips_howto_table_rel[r_type];
1332179407Sobrien    }
1333179407Sobrien}
1334179407Sobrien
1335179407Sobrien/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
1336179407Sobrien
1337179407Sobrienstatic void
1338179407Sobrienmips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
1339179407Sobrien{
1340218822Sdim  const struct elf_backend_data *bed;
1341179407Sobrien  unsigned int r_type;
1342179407Sobrien
1343179407Sobrien  r_type = ELF32_R_TYPE (dst->r_info);
1344218822Sdim  bed = get_elf_backend_data (abfd);
1345218822Sdim  cache_ptr->howto = bed->elf_backend_mips_rtype_to_howto (r_type, FALSE);
1346179407Sobrien
1347179407Sobrien  /* The addend for a GPREL16 or LITERAL relocation comes from the GP
1348179407Sobrien     value for the object file.  We get the addend now, rather than
1349179407Sobrien     when we do the relocation, because the symbol manipulations done
1350179407Sobrien     by the linker may cause us to lose track of the input BFD.  */
1351179407Sobrien  if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
1352179407Sobrien      && (r_type == (unsigned int) R_MIPS_GPREL16
1353179407Sobrien	  || r_type == (unsigned int) R_MIPS_LITERAL))
1354179407Sobrien    cache_ptr->addend = elf_gp (abfd);
1355179407Sobrien}
1356179407Sobrien
1357179407Sobrien/* Given a MIPS Elf_Internal_Rela, fill in an arelent structure.  */
1358179407Sobrien
1359179407Sobrienstatic void
1360179407Sobrienmips_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
1361179407Sobrien{
1362179407Sobrien  mips_info_to_howto_rel (abfd, cache_ptr, dst);
1363179407Sobrien
1364179407Sobrien  /* If we ever need to do any extra processing with dst->r_addend
1365179407Sobrien     (the field omitted in an Elf_Internal_Rel) we can do it here.  */
1366179407Sobrien}
1367179407Sobrien
1368179407Sobrien/* Determine whether a symbol is global for the purposes of splitting
1369179407Sobrien   the symbol table into global symbols and local symbols.  At least
1370179407Sobrien   on Irix 5, this split must be between section symbols and all other
1371179407Sobrien   symbols.  On most ELF targets the split is between static symbols
1372179407Sobrien   and externally visible symbols.  */
1373179407Sobrien
1374179407Sobrienstatic bfd_boolean
1375179407Sobrienmips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
1376179407Sobrien{
1377179407Sobrien  if (SGI_COMPAT (abfd))
1378179407Sobrien    return (sym->flags & BSF_SECTION_SYM) == 0;
1379179407Sobrien  else
1380179407Sobrien    return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
1381179407Sobrien	    || bfd_is_und_section (bfd_get_section (sym))
1382179407Sobrien	    || bfd_is_com_section (bfd_get_section (sym)));
1383179407Sobrien}
1384179407Sobrien
1385179407Sobrien/* Set the right machine number for a MIPS ELF file.  */
1386179407Sobrien
1387179407Sobrienstatic bfd_boolean
1388179407Sobrienmips_elf32_object_p (bfd *abfd)
1389179407Sobrien{
1390179407Sobrien  unsigned long mach;
1391179407Sobrien
1392179407Sobrien  /* Irix 5 and 6 are broken.  Object file symbol tables are not always
1393179407Sobrien     sorted correctly such that local symbols precede global symbols,
1394179407Sobrien     and the sh_info field in the symbol table is not always right.  */
1395179407Sobrien  if (SGI_COMPAT (abfd))
1396179407Sobrien    elf_bad_symtab (abfd) = TRUE;
1397179407Sobrien
1398179407Sobrien  if (ABI_N32_P (abfd))
1399179407Sobrien    return FALSE;
1400179407Sobrien
1401179407Sobrien  mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags);
1402179407Sobrien  bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach);
1403179407Sobrien
1404179407Sobrien  return TRUE;
1405179407Sobrien}
1406179407Sobrien
1407179407Sobrien/* MIPS ELF local labels start with '$', not 'L'.  */
1408179407Sobrien
1409179407Sobrienstatic bfd_boolean
1410179407Sobrienmips_elf_is_local_label_name (bfd *abfd, const char *name)
1411179407Sobrien{
1412179407Sobrien  if (name[0] == '$')
1413179407Sobrien    return TRUE;
1414179407Sobrien
1415179407Sobrien  /* On Irix 6, the labels go back to starting with '.', so we accept
1416179407Sobrien     the generic ELF local label syntax as well.  */
1417179407Sobrien  return _bfd_elf_is_local_label_name (abfd, name);
1418179407Sobrien}
1419179407Sobrien
1420179407Sobrien/* Support for core dump NOTE sections.  */
1421179407Sobrienstatic bfd_boolean
1422179407Sobrienelf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
1423179407Sobrien{
1424179407Sobrien  int offset;
1425218822Sdim  unsigned int size;
1426179407Sobrien
1427179407Sobrien  switch (note->descsz)
1428179407Sobrien    {
1429179407Sobrien      default:
1430179407Sobrien	return FALSE;
1431179407Sobrien
1432179407Sobrien      case 256:		/* Linux/MIPS */
1433179407Sobrien	/* pr_cursig */
1434179407Sobrien	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
1435179407Sobrien
1436179407Sobrien	/* pr_pid */
1437179407Sobrien	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
1438179407Sobrien
1439179407Sobrien	/* pr_reg */
1440179407Sobrien	offset = 72;
1441218822Sdim	size = 180;
1442179407Sobrien
1443179407Sobrien	break;
1444179407Sobrien    }
1445179407Sobrien
1446179407Sobrien  /* Make a ".reg/999" section.  */
1447179407Sobrien  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
1448218822Sdim					  size, note->descpos + offset);
1449179407Sobrien}
1450179407Sobrien
1451179407Sobrienstatic bfd_boolean
1452179407Sobrienelf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
1453179407Sobrien{
1454179407Sobrien  switch (note->descsz)
1455179407Sobrien    {
1456179407Sobrien      default:
1457179407Sobrien	return FALSE;
1458179407Sobrien
1459179407Sobrien      case 128:		/* Linux/MIPS elf_prpsinfo */
1460179407Sobrien	elf_tdata (abfd)->core_program
1461179407Sobrien	 = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
1462179407Sobrien	elf_tdata (abfd)->core_command
1463179407Sobrien	 = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
1464179407Sobrien    }
1465179407Sobrien
1466179407Sobrien  /* Note that for some reason, a spurious space is tacked
1467179407Sobrien     onto the end of the args in some (at least one anyway)
1468179407Sobrien     implementations, so strip it off if it exists.  */
1469179407Sobrien
1470179407Sobrien  {
1471179407Sobrien    char *command = elf_tdata (abfd)->core_command;
1472179407Sobrien    int n = strlen (command);
1473179407Sobrien
1474179407Sobrien    if (0 < n && command[n - 1] == ' ')
1475179407Sobrien      command[n - 1] = '\0';
1476179407Sobrien  }
1477179407Sobrien
1478179407Sobrien  return TRUE;
1479179407Sobrien}
1480179407Sobrien
1481179407Sobrien/* Depending on the target vector we generate some version of Irix
1482179407Sobrien   executables or "normal" MIPS ELF ABI executables.  */
1483179407Sobrienstatic irix_compat_t
1484179407Sobrienelf32_mips_irix_compat (bfd *abfd)
1485179407Sobrien{
1486179407Sobrien  if ((abfd->xvec == &bfd_elf32_bigmips_vec)
1487179407Sobrien      || (abfd->xvec == &bfd_elf32_littlemips_vec))
1488179407Sobrien    return ict_irix5;
1489179407Sobrien  else
1490179407Sobrien    return ict_none;
1491179407Sobrien}
1492179407Sobrien
1493179407Sobrien/* ECOFF swapping routines.  These are used when dealing with the
1494179407Sobrien   .mdebug section, which is in the ECOFF debugging format.  */
1495179407Sobrienstatic const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
1496179407Sobrien  /* Symbol table magic number.  */
1497179407Sobrien  magicSym,
1498179407Sobrien  /* Alignment of debugging information.  E.g., 4.  */
1499179407Sobrien  4,
1500179407Sobrien  /* Sizes of external symbolic information.  */
1501179407Sobrien  sizeof (struct hdr_ext),
1502179407Sobrien  sizeof (struct dnr_ext),
1503179407Sobrien  sizeof (struct pdr_ext),
1504179407Sobrien  sizeof (struct sym_ext),
1505179407Sobrien  sizeof (struct opt_ext),
1506179407Sobrien  sizeof (struct fdr_ext),
1507179407Sobrien  sizeof (struct rfd_ext),
1508179407Sobrien  sizeof (struct ext_ext),
1509179407Sobrien  /* Functions to swap in external symbolic data.  */
1510179407Sobrien  ecoff_swap_hdr_in,
1511179407Sobrien  ecoff_swap_dnr_in,
1512179407Sobrien  ecoff_swap_pdr_in,
1513179407Sobrien  ecoff_swap_sym_in,
1514179407Sobrien  ecoff_swap_opt_in,
1515179407Sobrien  ecoff_swap_fdr_in,
1516179407Sobrien  ecoff_swap_rfd_in,
1517179407Sobrien  ecoff_swap_ext_in,
1518179407Sobrien  _bfd_ecoff_swap_tir_in,
1519179407Sobrien  _bfd_ecoff_swap_rndx_in,
1520179407Sobrien  /* Functions to swap out external symbolic data.  */
1521179407Sobrien  ecoff_swap_hdr_out,
1522179407Sobrien  ecoff_swap_dnr_out,
1523179407Sobrien  ecoff_swap_pdr_out,
1524179407Sobrien  ecoff_swap_sym_out,
1525179407Sobrien  ecoff_swap_opt_out,
1526179407Sobrien  ecoff_swap_fdr_out,
1527179407Sobrien  ecoff_swap_rfd_out,
1528179407Sobrien  ecoff_swap_ext_out,
1529179407Sobrien  _bfd_ecoff_swap_tir_out,
1530179407Sobrien  _bfd_ecoff_swap_rndx_out,
1531179407Sobrien  /* Function to read in symbolic data.  */
1532179407Sobrien  _bfd_mips_elf_read_ecoff_info
1533179407Sobrien};
1534179407Sobrien
1535179407Sobrien#define ELF_ARCH			bfd_arch_mips
1536179407Sobrien#define ELF_MACHINE_CODE		EM_MIPS
1537179407Sobrien
1538179407Sobrien#define elf_backend_collect		TRUE
1539179407Sobrien#define elf_backend_type_change_ok	TRUE
1540179407Sobrien#define elf_backend_can_gc_sections	TRUE
1541179407Sobrien#define elf_info_to_howto		mips_info_to_howto_rela
1542179407Sobrien#define elf_info_to_howto_rel		mips_info_to_howto_rel
1543179407Sobrien#define elf_backend_sym_is_global	mips_elf_sym_is_global
1544179407Sobrien#define elf_backend_object_p		mips_elf32_object_p
1545179407Sobrien#define elf_backend_symbol_processing	_bfd_mips_elf_symbol_processing
1546179407Sobrien#define elf_backend_section_processing	_bfd_mips_elf_section_processing
1547179407Sobrien#define elf_backend_section_from_shdr	_bfd_mips_elf_section_from_shdr
1548179407Sobrien#define elf_backend_fake_sections	_bfd_mips_elf_fake_sections
1549179407Sobrien#define elf_backend_section_from_bfd_section \
1550179407Sobrien					_bfd_mips_elf_section_from_bfd_section
1551179407Sobrien#define elf_backend_add_symbol_hook	_bfd_mips_elf_add_symbol_hook
1552179407Sobrien#define elf_backend_link_output_symbol_hook \
1553179407Sobrien					_bfd_mips_elf_link_output_symbol_hook
1554179407Sobrien#define elf_backend_create_dynamic_sections \
1555179407Sobrien					_bfd_mips_elf_create_dynamic_sections
1556179407Sobrien#define elf_backend_check_relocs	_bfd_mips_elf_check_relocs
1557218822Sdim#define elf_backend_merge_symbol_attribute \
1558218822Sdim					_bfd_mips_elf_merge_symbol_attribute
1559179407Sobrien#define elf_backend_adjust_dynamic_symbol \
1560179407Sobrien					_bfd_mips_elf_adjust_dynamic_symbol
1561179407Sobrien#define elf_backend_always_size_sections \
1562179407Sobrien					_bfd_mips_elf_always_size_sections
1563179407Sobrien#define elf_backend_size_dynamic_sections \
1564179407Sobrien					_bfd_mips_elf_size_dynamic_sections
1565218822Sdim#define elf_backend_init_index_section	_bfd_elf_init_1_index_section
1566179407Sobrien#define elf_backend_relocate_section	_bfd_mips_elf_relocate_section
1567179407Sobrien#define elf_backend_finish_dynamic_symbol \
1568179407Sobrien					_bfd_mips_elf_finish_dynamic_symbol
1569179407Sobrien#define elf_backend_finish_dynamic_sections \
1570179407Sobrien					_bfd_mips_elf_finish_dynamic_sections
1571179407Sobrien#define elf_backend_final_write_processing \
1572179407Sobrien					_bfd_mips_elf_final_write_processing
1573179407Sobrien#define elf_backend_additional_program_headers \
1574179407Sobrien					_bfd_mips_elf_additional_program_headers
1575179407Sobrien#define elf_backend_modify_segment_map	_bfd_mips_elf_modify_segment_map
1576179407Sobrien#define elf_backend_gc_mark_hook	_bfd_mips_elf_gc_mark_hook
1577179407Sobrien#define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
1578179407Sobrien#define elf_backend_copy_indirect_symbol \
1579179407Sobrien					_bfd_mips_elf_copy_indirect_symbol
1580179407Sobrien#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
1581179407Sobrien#define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
1582179407Sobrien#define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
1583179407Sobrien#define elf_backend_ecoff_debug_swap	&mips_elf32_ecoff_debug_swap
1584179407Sobrien
1585179407Sobrien#define elf_backend_got_header_size	(4 * MIPS_RESERVED_GOTNO)
1586179407Sobrien#define elf_backend_may_use_rel_p	1
1587179407Sobrien#define elf_backend_may_use_rela_p	0
1588179407Sobrien#define elf_backend_default_use_rela_p	0
1589179407Sobrien#define elf_backend_sign_extend_vma	TRUE
1590179407Sobrien
1591179407Sobrien#define elf_backend_discard_info	_bfd_mips_elf_discard_info
1592179407Sobrien#define elf_backend_ignore_discarded_relocs \
1593179407Sobrien					_bfd_mips_elf_ignore_discarded_relocs
1594179407Sobrien#define elf_backend_mips_irix_compat	elf32_mips_irix_compat
1595179407Sobrien#define elf_backend_mips_rtype_to_howto	mips_elf32_rtype_to_howto
1596179407Sobrien#define bfd_elf32_bfd_is_local_label_name \
1597179407Sobrien					mips_elf_is_local_label_name
1598179407Sobrien#define bfd_elf32_find_nearest_line	_bfd_mips_elf_find_nearest_line
1599218822Sdim#define bfd_elf32_find_inliner_info	_bfd_mips_elf_find_inliner_info
1600179407Sobrien#define bfd_elf32_new_section_hook	_bfd_mips_elf_new_section_hook
1601179407Sobrien#define bfd_elf32_set_section_contents	_bfd_mips_elf_set_section_contents
1602179407Sobrien#define bfd_elf32_bfd_get_relocated_section_contents \
1603179407Sobrien				_bfd_elf_mips_get_relocated_section_contents
1604179407Sobrien#define bfd_elf32_bfd_link_hash_table_create \
1605179407Sobrien					_bfd_mips_elf_link_hash_table_create
1606179407Sobrien#define bfd_elf32_bfd_final_link	_bfd_mips_elf_final_link
1607179407Sobrien#define bfd_elf32_bfd_merge_private_bfd_data \
1608179407Sobrien					_bfd_mips_elf_merge_private_bfd_data
1609179407Sobrien#define bfd_elf32_bfd_set_private_flags	_bfd_mips_elf_set_private_flags
1610179407Sobrien#define bfd_elf32_bfd_print_private_bfd_data \
1611179407Sobrien					_bfd_mips_elf_print_private_bfd_data
1612179407Sobrien
1613179407Sobrien/* Support for SGI-ish mips targets.  */
1614179407Sobrien#define TARGET_LITTLE_SYM		bfd_elf32_littlemips_vec
1615179407Sobrien#define TARGET_LITTLE_NAME		"elf32-littlemips"
1616179407Sobrien#define TARGET_BIG_SYM			bfd_elf32_bigmips_vec
1617179407Sobrien#define TARGET_BIG_NAME			"elf32-bigmips"
1618179407Sobrien
1619179407Sobrien/* The SVR4 MIPS ABI says that this should be 0x10000, but Irix 5 uses
1620179407Sobrien   a value of 0x1000, and we are compatible.  */
1621179407Sobrien#define ELF_MAXPAGESIZE			0x1000
1622218822Sdim#define ELF_COMMONPAGESIZE		0x1000
1623179407Sobrien
1624179407Sobrien#include "elf32-target.h"
1625179407Sobrien
1626179407Sobrien/* Support for traditional mips targets.  */
1627179407Sobrien#undef TARGET_LITTLE_SYM
1628179407Sobrien#undef TARGET_LITTLE_NAME
1629179407Sobrien#undef TARGET_BIG_SYM
1630179407Sobrien#undef TARGET_BIG_NAME
1631179407Sobrien
1632179407Sobrien#undef ELF_MAXPAGESIZE
1633218822Sdim#undef ELF_COMMONPAGESIZE
1634179407Sobrien
1635179407Sobrien#define TARGET_LITTLE_SYM               bfd_elf32_tradlittlemips_vec
1636179407Sobrien#define TARGET_LITTLE_NAME              "elf32-tradlittlemips"
1637179407Sobrien#define TARGET_BIG_SYM                  bfd_elf32_tradbigmips_vec
1638179407Sobrien#define TARGET_BIG_NAME                 "elf32-tradbigmips"
1639179407Sobrien
1640218822Sdim/* The MIPS ABI says at Page 5-1:
1641218822Sdim   Virtual addresses and file offsets for MIPS segments are congruent
1642218822Sdim   modulo 64 KByte (0x10000) or larger powers of 2.  Because 64 KBytes
1643218822Sdim   is the maximum page size, the files are suitable for paging
1644218822Sdim   regardless of physical page size.  */
1645179407Sobrien#define ELF_MAXPAGESIZE			0x10000
1646218822Sdim#define ELF_COMMONPAGESIZE		0x1000
1647179407Sobrien#define elf32_bed			elf32_tradbed
1648179407Sobrien
1649179407Sobrien/* Include the target file again for this target.  */
1650179407Sobrien#include "elf32-target.h"
1651218822Sdim
1652218822Sdim
1653218822Sdim/* Specific to VxWorks.  */
1654218822Sdimstatic reloc_howto_type mips_vxworks_copy_howto_rela =
1655218822Sdim  HOWTO (R_MIPS_COPY,		/* type */
1656218822Sdim	 0,			/* rightshift */
1657218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1658218822Sdim	 32,			/* bitsize */
1659218822Sdim	 FALSE,			/* pc_relative */
1660218822Sdim	 0,			/* bitpos */
1661218822Sdim	 complain_overflow_bitfield, /* complain_on_overflow */
1662218822Sdim	 bfd_elf_generic_reloc,	/* special_function */
1663218822Sdim	 "R_MIPS_COPY",		/* name */
1664218822Sdim	 FALSE,			/* partial_inplace */
1665218822Sdim	 0x0,         		/* src_mask */
1666218822Sdim	 0x0,		        /* dst_mask */
1667218822Sdim	 FALSE);		/* pcrel_offset */
1668218822Sdim
1669218822Sdim/* Specific to VxWorks.  */
1670218822Sdimstatic reloc_howto_type mips_vxworks_jump_slot_howto_rela =
1671218822Sdim  HOWTO (R_MIPS_JUMP_SLOT,	/* type */
1672218822Sdim	 0,			/* rightshift */
1673218822Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1674218822Sdim	 32,			/* bitsize */
1675218822Sdim	 FALSE,			/* pc_relative */
1676218822Sdim	 0,			/* bitpos */
1677218822Sdim	 complain_overflow_bitfield, /* complain_on_overflow */
1678218822Sdim	 bfd_elf_generic_reloc,	/* special_function */
1679218822Sdim	 "R_MIPS_JUMP_SLOT",	/* name */
1680218822Sdim	 FALSE,			/* partial_inplace */
1681218822Sdim	 0x0,         		/* src_mask */
1682218822Sdim	 0x0,		        /* dst_mask */
1683218822Sdim	 FALSE);		/* pcrel_offset */
1684218822Sdim
1685218822Sdim/* Implement elf_backend_bfd_reloc_type_lookup for VxWorks.  */
1686218822Sdim
1687218822Sdimstatic reloc_howto_type *
1688218822Sdimmips_vxworks_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
1689218822Sdim{
1690218822Sdim  switch (code)
1691218822Sdim    {
1692218822Sdim    case BFD_RELOC_MIPS_COPY:
1693218822Sdim      return &mips_vxworks_copy_howto_rela;
1694218822Sdim    case BFD_RELOC_MIPS_JUMP_SLOT:
1695218822Sdim      return &mips_vxworks_jump_slot_howto_rela;
1696218822Sdim    default:
1697218822Sdim      return bfd_elf32_bfd_reloc_type_lookup (abfd, code);
1698218822Sdim    }
1699218822Sdim}
1700218822Sdim
1701218822Sdimstatic reloc_howto_type *
1702218822Sdimmips_vxworks_bfd_reloc_name_lookup (bfd *abfd, const char *r_name)
1703218822Sdim{
1704218822Sdim  if (strcasecmp (mips_vxworks_copy_howto_rela.name, r_name) == 0)
1705218822Sdim    return &mips_vxworks_copy_howto_rela;
1706218822Sdim  if (strcasecmp (mips_vxworks_jump_slot_howto_rela.name, r_name) == 0)
1707218822Sdim    return &mips_vxworks_jump_slot_howto_rela;
1708218822Sdim
1709218822Sdim  return bfd_elf32_bfd_reloc_name_lookup (abfd, r_name);
1710218822Sdim}
1711218822Sdim
1712218822Sdim/* Implement elf_backend_mips_rtype_to_lookup for VxWorks.  */
1713218822Sdim
1714218822Sdimstatic reloc_howto_type *
1715218822Sdimmips_vxworks_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p)
1716218822Sdim{
1717218822Sdim  switch (r_type)
1718218822Sdim    {
1719218822Sdim    case R_MIPS_COPY:
1720218822Sdim      return &mips_vxworks_copy_howto_rela;
1721218822Sdim    case R_MIPS_JUMP_SLOT:
1722218822Sdim      return &mips_vxworks_jump_slot_howto_rela;
1723218822Sdim    default:
1724218822Sdim      return mips_elf32_rtype_to_howto (r_type, rela_p);
1725218822Sdim    }
1726218822Sdim}
1727218822Sdim
1728218822Sdim/* Implement elf_backend_final_write_processing for VxWorks.  */
1729218822Sdim
1730218822Sdimstatic void
1731218822Sdimmips_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
1732218822Sdim{
1733218822Sdim  _bfd_mips_elf_final_write_processing (abfd, linker);
1734218822Sdim  elf_vxworks_final_write_processing (abfd, linker);
1735218822Sdim}
1736218822Sdim
1737218822Sdim#undef TARGET_LITTLE_SYM
1738218822Sdim#undef TARGET_LITTLE_NAME
1739218822Sdim#undef TARGET_BIG_SYM
1740218822Sdim#undef TARGET_BIG_NAME
1741218822Sdim
1742218822Sdim#undef ELF_MAXPAGESIZE
1743218822Sdim#undef ELF_COMMONPAGESIZE
1744218822Sdim
1745218822Sdim#define TARGET_LITTLE_SYM               bfd_elf32_littlemips_vxworks_vec
1746218822Sdim#define TARGET_LITTLE_NAME              "elf32-littlemips-vxworks"
1747218822Sdim#define TARGET_BIG_SYM                  bfd_elf32_bigmips_vxworks_vec
1748218822Sdim#define TARGET_BIG_NAME                 "elf32-bigmips-vxworks"
1749218822Sdim
1750218822Sdim#undef elf32_bed
1751218822Sdim#define elf32_bed			elf32_mips_vxworks_bed
1752218822Sdim
1753218822Sdim#define ELF_MAXPAGESIZE			0x1000
1754218822Sdim#define ELF_COMMONPAGESIZE		0x1000
1755218822Sdim
1756218822Sdim#undef elf_backend_want_got_plt
1757218822Sdim#define elf_backend_want_got_plt		1
1758218822Sdim#undef elf_backend_want_plt_sym
1759218822Sdim#define elf_backend_want_plt_sym		1
1760218822Sdim#undef elf_backend_got_symbol_offset
1761218822Sdim#define elf_backend_got_symbol_offset		0
1762218822Sdim#undef elf_backend_want_dynbss
1763218822Sdim#define elf_backend_want_dynbss			1
1764218822Sdim#undef elf_backend_may_use_rel_p
1765218822Sdim#define elf_backend_may_use_rel_p		0
1766218822Sdim#undef elf_backend_may_use_rela_p
1767218822Sdim#define elf_backend_may_use_rela_p		1
1768218822Sdim#undef elf_backend_default_use_rela_p
1769218822Sdim#define elf_backend_default_use_rela_p		1
1770218822Sdim#undef elf_backend_got_header_size
1771218822Sdim#define elf_backend_got_header_size		(4 * 3)
1772218822Sdim#undef elf_backend_plt_readonly
1773218822Sdim#define elf_backend_plt_readonly		1
1774218822Sdim
1775218822Sdim#undef bfd_elf32_bfd_reloc_type_lookup
1776218822Sdim#define bfd_elf32_bfd_reloc_type_lookup \
1777218822Sdim  mips_vxworks_bfd_reloc_type_lookup
1778218822Sdim#undef bfd_elf32_bfd_reloc_name_lookup
1779218822Sdim#define bfd_elf32_bfd_reloc_name_lookup \
1780218822Sdim  mips_vxworks_bfd_reloc_name_lookup
1781218822Sdim#undef elf_backend_mips_rtype_to_howto
1782218822Sdim#define elf_backend_mips_rtype_to_howto	\
1783218822Sdim  mips_vxworks_rtype_to_howto
1784218822Sdim#undef elf_backend_adjust_dynamic_symbol
1785218822Sdim#define elf_backend_adjust_dynamic_symbol \
1786218822Sdim  _bfd_mips_vxworks_adjust_dynamic_symbol
1787218822Sdim#undef elf_backend_finish_dynamic_symbol
1788218822Sdim#define elf_backend_finish_dynamic_symbol \
1789218822Sdim  _bfd_mips_vxworks_finish_dynamic_symbol
1790218822Sdim#undef bfd_elf32_bfd_link_hash_table_create
1791218822Sdim#define bfd_elf32_bfd_link_hash_table_create \
1792218822Sdim  _bfd_mips_vxworks_link_hash_table_create
1793218822Sdim#undef elf_backend_add_symbol_hook
1794218822Sdim#define elf_backend_add_symbol_hook \
1795218822Sdim  elf_vxworks_add_symbol_hook
1796218822Sdim#undef elf_backend_link_output_symbol_hook
1797218822Sdim#define elf_backend_link_output_symbol_hook \
1798218822Sdim  elf_vxworks_link_output_symbol_hook
1799218822Sdim#undef elf_backend_emit_relocs
1800218822Sdim#define elf_backend_emit_relocs \
1801218822Sdim  elf_vxworks_emit_relocs
1802218822Sdim#undef elf_backend_final_write_processing
1803218822Sdim#define elf_backend_final_write_processing \
1804218822Sdim  mips_vxworks_final_write_processing
1805218822Sdim
1806218822Sdim#undef elf_backend_additional_program_headers
1807218822Sdim#undef elf_backend_modify_segment_map
1808218822Sdim#undef elf_backend_symbol_processing
1809218822Sdim/* NOTE: elf_backend_rela_normal is not defined for MIPS.  */
1810218822Sdim
1811218822Sdim#include "elf32-target.h"
1812