xref: /openbsd-src/gnu/usr.bin/binutils/bfd/elf32-mips.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* MIPS-specific support for 32-bit ELF
2c074d1c9Sdrahn    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3c074d1c9Sdrahn    2003 Free Software Foundation, Inc.
42159047fSniklas 
52159047fSniklas    Most of the information added by Ian Lance Taylor, Cygnus Support,
62159047fSniklas    <ian@cygnus.com>.
7b305b0f1Sespie    N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
8b305b0f1Sespie    <mark@codesourcery.com>
9b55d4692Sfgsch    Traditional MIPS targets support added by Koundinya.K, Dansk Data
10b55d4692Sfgsch    Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
112159047fSniklas 
122159047fSniklas This file is part of BFD, the Binary File Descriptor library.
132159047fSniklas 
142159047fSniklas This program is free software; you can redistribute it and/or modify
152159047fSniklas it under the terms of the GNU General Public License as published by
162159047fSniklas the Free Software Foundation; either version 2 of the License, or
172159047fSniklas (at your option) any later version.
182159047fSniklas 
192159047fSniklas This program is distributed in the hope that it will be useful,
202159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
212159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
222159047fSniklas GNU General Public License for more details.
232159047fSniklas 
242159047fSniklas You should have received a copy of the GNU General Public License
252159047fSniklas along with this program; if not, write to the Free Software
262159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
272159047fSniklas 
28c88b1d6cSniklas /* This file handles MIPS ELF targets.  SGI Irix 5 uses a slightly
29c88b1d6cSniklas    different MIPS ELF from other targets.  This matters when linking.
30c88b1d6cSniklas    This file supports both, switching at runtime.  */
31c88b1d6cSniklas 
322159047fSniklas #include "bfd.h"
332159047fSniklas #include "sysdep.h"
342159047fSniklas #include "libbfd.h"
352159047fSniklas #include "bfdlink.h"
362159047fSniklas #include "genlink.h"
372159047fSniklas #include "elf-bfd.h"
38c074d1c9Sdrahn #include "elfxx-mips.h"
392159047fSniklas #include "elf/mips.h"
402159047fSniklas 
412159047fSniklas /* Get the ECOFF swapping routines.  */
422159047fSniklas #include "coff/sym.h"
432159047fSniklas #include "coff/symconst.h"
442159047fSniklas #include "coff/internal.h"
452159047fSniklas #include "coff/ecoff.h"
462159047fSniklas #include "coff/mips.h"
47b55d4692Sfgsch #define ECOFF_SIGNED_32
482159047fSniklas #include "ecoffswap.h"
492159047fSniklas 
50*007c2a45Smiod static bfd_reloc_status_type gprel32_with_gp
51*007c2a45Smiod   (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma);
52c074d1c9Sdrahn static bfd_reloc_status_type mips_elf_gprel32_reloc
53*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
54b305b0f1Sespie static bfd_reloc_status_type mips32_64bit_reloc
55*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
56b305b0f1Sespie static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
57*007c2a45Smiod   (bfd *, bfd_reloc_code_real_type);
58c074d1c9Sdrahn static reloc_howto_type *mips_elf32_rtype_to_howto
59*007c2a45Smiod   (unsigned int, bfd_boolean);
60b305b0f1Sespie static void mips_info_to_howto_rel
61*007c2a45Smiod   (bfd *, arelent *, Elf_Internal_Rela *);
62b305b0f1Sespie static void mips_info_to_howto_rela
63*007c2a45Smiod   (bfd *, arelent *, Elf_Internal_Rela *);
64c074d1c9Sdrahn static bfd_boolean mips_elf_sym_is_global
65*007c2a45Smiod   (bfd *, asymbol *);
66c074d1c9Sdrahn static bfd_boolean mips_elf32_object_p
67*007c2a45Smiod   (bfd *);
68c074d1c9Sdrahn static bfd_boolean mips_elf_is_local_label_name
69*007c2a45Smiod   (bfd *, const char *);
70b305b0f1Sespie static bfd_reloc_status_type mips16_jump_reloc
71*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
72b305b0f1Sespie static bfd_reloc_status_type mips16_gprel_reloc
73*007c2a45Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
74b305b0f1Sespie static bfd_reloc_status_type mips_elf_final_gp
75*007c2a45Smiod   (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
76c074d1c9Sdrahn static bfd_boolean mips_elf_assign_gp
77*007c2a45Smiod   (bfd *, bfd_vma *);
78c074d1c9Sdrahn static bfd_boolean elf32_mips_grok_prstatus
79*007c2a45Smiod   (bfd *, Elf_Internal_Note *);
80c074d1c9Sdrahn static bfd_boolean elf32_mips_grok_psinfo
81*007c2a45Smiod   (bfd *, Elf_Internal_Note *);
82c074d1c9Sdrahn static irix_compat_t elf32_mips_irix_compat
83*007c2a45Smiod   (bfd *);
84b55d4692Sfgsch 
85c074d1c9Sdrahn extern const bfd_target bfd_elf32_bigmips_vec;
86c074d1c9Sdrahn extern const bfd_target bfd_elf32_littlemips_vec;
87b55d4692Sfgsch 
88b305b0f1Sespie /* Nonzero if ABFD is using the N32 ABI.  */
89b305b0f1Sespie #define ABI_N32_P(abfd) \
90b305b0f1Sespie   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
91b305b0f1Sespie 
92b305b0f1Sespie /* Whether we are trying to be compatible with IRIX at all.  */
93b305b0f1Sespie #define SGI_COMPAT(abfd) \
94c074d1c9Sdrahn   (elf32_mips_irix_compat (abfd) != ict_none)
95b305b0f1Sespie 
96c88b1d6cSniklas /* The number of local .got entries we reserve.  */
97c88b1d6cSniklas #define MIPS_RESERVED_GOTNO (2)
98c88b1d6cSniklas 
99b305b0f1Sespie /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
100b305b0f1Sespie    from smaller values.  Start with zero, widen, *then* decrement.  */
101b305b0f1Sespie #define MINUS_ONE	(((bfd_vma)0) - 1)
1022159047fSniklas 
103c074d1c9Sdrahn /* The relocation table used for SHT_REL sections.  */
104c074d1c9Sdrahn 
105c074d1c9Sdrahn static reloc_howto_type elf_mips_howto_table_rel[] =
1062159047fSniklas {
1072159047fSniklas   /* No relocation.  */
1082159047fSniklas   HOWTO (R_MIPS_NONE,		/* type */
1092159047fSniklas 	 0,			/* rightshift */
1102159047fSniklas 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1112159047fSniklas 	 0,			/* bitsize */
112c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1132159047fSniklas 	 0,			/* bitpos */
1142159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
115*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1162159047fSniklas 	 "R_MIPS_NONE",		/* name */
117c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1182159047fSniklas 	 0,			/* src_mask */
1192159047fSniklas 	 0,			/* dst_mask */
120c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1212159047fSniklas 
1222159047fSniklas   /* 16 bit relocation.  */
1232159047fSniklas   HOWTO (R_MIPS_16,		/* type */
1242159047fSniklas 	 0,			/* rightshift */
125c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1262159047fSniklas 	 16,			/* bitsize */
127c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1282159047fSniklas 	 0,			/* bitpos */
129c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
130*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1312159047fSniklas 	 "R_MIPS_16",		/* name */
132c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
133c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
134c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
135c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1362159047fSniklas 
1372159047fSniklas   /* 32 bit relocation.  */
1382159047fSniklas   HOWTO (R_MIPS_32,		/* type */
1392159047fSniklas 	 0,			/* rightshift */
1402159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1412159047fSniklas 	 32,			/* bitsize */
142c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1432159047fSniklas 	 0,			/* bitpos */
144c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
145*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1462159047fSniklas 	 "R_MIPS_32",		/* name */
147c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1482159047fSniklas 	 0xffffffff,		/* src_mask */
1492159047fSniklas 	 0xffffffff,		/* dst_mask */
150c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1512159047fSniklas 
1522159047fSniklas   /* 32 bit symbol relative relocation.  */
1532159047fSniklas   HOWTO (R_MIPS_REL32,		/* type */
1542159047fSniklas 	 0,			/* rightshift */
1552159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1562159047fSniklas 	 32,			/* bitsize */
157c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1582159047fSniklas 	 0,			/* bitpos */
159c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
160*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1612159047fSniklas 	 "R_MIPS_REL32",	/* name */
162c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1632159047fSniklas 	 0xffffffff,		/* src_mask */
1642159047fSniklas 	 0xffffffff,		/* dst_mask */
165c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1662159047fSniklas 
167b55d4692Sfgsch   /* 26 bit jump address.  */
1682159047fSniklas   HOWTO (R_MIPS_26,		/* type */
1692159047fSniklas 	 2,			/* rightshift */
1702159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1712159047fSniklas 	 26,			/* bitsize */
172c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1732159047fSniklas 	 0,			/* bitpos */
1742159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1752159047fSniklas 	 			/* This needs complex overflow
1762159047fSniklas 				   detection, because the upper four
177b55d4692Sfgsch 				   bits must match the PC + 4.  */
178*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
1792159047fSniklas 	 "R_MIPS_26",		/* name */
180c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
181c074d1c9Sdrahn 	 0x03ffffff,		/* src_mask */
182c074d1c9Sdrahn 	 0x03ffffff,		/* dst_mask */
183c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1842159047fSniklas 
1852159047fSniklas   /* High 16 bits of symbol value.  */
1862159047fSniklas   HOWTO (R_MIPS_HI16,		/* type */
187*007c2a45Smiod 	 16,			/* rightshift */
1882159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1892159047fSniklas 	 16,			/* bitsize */
190c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1912159047fSniklas 	 0,			/* bitpos */
1922159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
193*007c2a45Smiod 	 _bfd_mips_elf_hi16_reloc, /* special_function */
1942159047fSniklas 	 "R_MIPS_HI16",		/* name */
195c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
196c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
197c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
198c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1992159047fSniklas 
2002159047fSniklas   /* Low 16 bits of symbol value.  */
2012159047fSniklas   HOWTO (R_MIPS_LO16,		/* type */
2022159047fSniklas 	 0,			/* rightshift */
2032159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2042159047fSniklas 	 16,			/* bitsize */
205c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2062159047fSniklas 	 0,			/* bitpos */
2072159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
208*007c2a45Smiod 	 _bfd_mips_elf_lo16_reloc, /* special_function */
2092159047fSniklas 	 "R_MIPS_LO16",		/* name */
210c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
211c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
212c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
213c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2142159047fSniklas 
2152159047fSniklas   /* GP relative reference.  */
2162159047fSniklas   HOWTO (R_MIPS_GPREL16,	/* type */
2172159047fSniklas 	 0,			/* rightshift */
2182159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2192159047fSniklas 	 16,			/* bitsize */
220c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2212159047fSniklas 	 0,			/* bitpos */
2222159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
223c074d1c9Sdrahn 	 _bfd_mips_elf32_gprel16_reloc, /* special_function */
2242159047fSniklas 	 "R_MIPS_GPREL16",	/* name */
225c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
226c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
227c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
228c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2292159047fSniklas 
2302159047fSniklas   /* Reference to literal section.  */
2312159047fSniklas   HOWTO (R_MIPS_LITERAL,	/* type */
2322159047fSniklas 	 0,			/* rightshift */
2332159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2342159047fSniklas 	 16,			/* bitsize */
235c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2362159047fSniklas 	 0,			/* bitpos */
2372159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
238c074d1c9Sdrahn 	 _bfd_mips_elf32_gprel16_reloc, /* special_function */
2392159047fSniklas 	 "R_MIPS_LITERAL",	/* name */
240c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
241c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
242c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
243c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2442159047fSniklas 
2452159047fSniklas   /* Reference to global offset table.  */
2462159047fSniklas   HOWTO (R_MIPS_GOT16,		/* type */
2472159047fSniklas 	 0,			/* rightshift */
2482159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2492159047fSniklas 	 16,			/* bitsize */
250c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2512159047fSniklas 	 0,			/* bitpos */
2522159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
253*007c2a45Smiod 	 _bfd_mips_elf_got16_reloc, /* special_function */
2542159047fSniklas 	 "R_MIPS_GOT16",	/* name */
255c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
256c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
257c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
258c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2592159047fSniklas 
2602159047fSniklas   /* 16 bit PC relative reference.  */
2612159047fSniklas   HOWTO (R_MIPS_PC16,		/* type */
2622159047fSniklas 	 0,			/* rightshift */
2632159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2642159047fSniklas 	 16,			/* bitsize */
265c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
2662159047fSniklas 	 0,			/* bitpos */
2672159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
268*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
2692159047fSniklas 	 "R_MIPS_PC16",		/* name */
270c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
271c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
272c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
273c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
2742159047fSniklas 
2752159047fSniklas   /* 16 bit call through global offset table.  */
2762159047fSniklas   HOWTO (R_MIPS_CALL16,		/* type */
2772159047fSniklas 	 0,			/* rightshift */
2782159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2792159047fSniklas 	 16,			/* bitsize */
280c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2812159047fSniklas 	 0,			/* bitpos */
2822159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
283*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
2842159047fSniklas 	 "R_MIPS_CALL16",	/* name */
285c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
286c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
287c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
288c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2892159047fSniklas 
2902159047fSniklas   /* 32 bit GP relative reference.  */
2912159047fSniklas   HOWTO (R_MIPS_GPREL32,	/* type */
2922159047fSniklas 	 0,			/* rightshift */
2932159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2942159047fSniklas 	 32,			/* bitsize */
295c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2962159047fSniklas 	 0,			/* bitpos */
297c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
298c074d1c9Sdrahn 	 mips_elf_gprel32_reloc, /* special_function */
2992159047fSniklas 	 "R_MIPS_GPREL32",	/* name */
300c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3012159047fSniklas 	 0xffffffff,		/* src_mask */
3022159047fSniklas 	 0xffffffff,		/* dst_mask */
303c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3042159047fSniklas 
3052159047fSniklas   /* The remaining relocs are defined on Irix 5, although they are
3062159047fSniklas      not defined by the ABI.  */
307b305b0f1Sespie   EMPTY_HOWTO (13),
308b305b0f1Sespie   EMPTY_HOWTO (14),
309b305b0f1Sespie   EMPTY_HOWTO (15),
3102159047fSniklas 
3112159047fSniklas   /* A 5 bit shift field.  */
3122159047fSniklas   HOWTO (R_MIPS_SHIFT5,		/* type */
3132159047fSniklas 	 0,			/* rightshift */
3142159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3152159047fSniklas 	 5,			/* bitsize */
316c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
3172159047fSniklas 	 6,			/* bitpos */
3182159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
319*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
3202159047fSniklas 	 "R_MIPS_SHIFT5",	/* name */
321c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3222159047fSniklas 	 0x000007c0,		/* src_mask */
3232159047fSniklas 	 0x000007c0,		/* dst_mask */
324c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3252159047fSniklas 
3262159047fSniklas   /* A 6 bit shift field.  */
3272159047fSniklas   /* FIXME: This is not handled correctly; a special function is
3282159047fSniklas      needed to put the most significant bit in the right place.  */
3292159047fSniklas   HOWTO (R_MIPS_SHIFT6,		/* type */
3302159047fSniklas 	 0,			/* rightshift */
3312159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3322159047fSniklas 	 6,			/* bitsize */
333c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
3342159047fSniklas 	 6,			/* bitpos */
3352159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
336*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
3372159047fSniklas 	 "R_MIPS_SHIFT6",	/* name */
338c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3392159047fSniklas 	 0x000007c4,		/* src_mask */
3402159047fSniklas 	 0x000007c4,		/* dst_mask */
341c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3422159047fSniklas 
343b305b0f1Sespie   /* A 64 bit relocation.  */
344e93f7393Sniklas   HOWTO (R_MIPS_64,		/* type */
345e93f7393Sniklas 	 0,			/* rightshift */
346b305b0f1Sespie 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
347b305b0f1Sespie 	 64,			/* bitsize */
348c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
349e93f7393Sniklas 	 0,			/* bitpos */
350c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
351e93f7393Sniklas 	 mips32_64bit_reloc,	/* special_function */
352e93f7393Sniklas 	 "R_MIPS_64",		/* name */
353c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
354b305b0f1Sespie 	 MINUS_ONE,		/* src_mask */
355b305b0f1Sespie 	 MINUS_ONE,		/* dst_mask */
356c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3572159047fSniklas 
3582159047fSniklas   /* Displacement in the global offset table.  */
3592159047fSniklas   HOWTO (R_MIPS_GOT_DISP,	/* type */
3602159047fSniklas 	 0,			/* rightshift */
3612159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3622159047fSniklas 	 16,			/* bitsize */
363c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
3642159047fSniklas 	 0,			/* bitpos */
365c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
366*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
3672159047fSniklas 	 "R_MIPS_GOT_DISP",	/* name */
368c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3692159047fSniklas 	 0x0000ffff,		/* src_mask */
3702159047fSniklas 	 0x0000ffff,		/* dst_mask */
371c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3722159047fSniklas 
3732159047fSniklas   /* Displacement to page pointer in the global offset table.  */
3742159047fSniklas   HOWTO (R_MIPS_GOT_PAGE,	/* type */
3752159047fSniklas 	 0,			/* rightshift */
3762159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3772159047fSniklas 	 16,			/* bitsize */
378c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
3792159047fSniklas 	 0,			/* bitpos */
380c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
381*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
3822159047fSniklas 	 "R_MIPS_GOT_PAGE",	/* name */
383c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3842159047fSniklas 	 0x0000ffff,		/* src_mask */
3852159047fSniklas 	 0x0000ffff,		/* dst_mask */
386c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
3872159047fSniklas 
3882159047fSniklas   /* Offset from page pointer in the global offset table.  */
3892159047fSniklas   HOWTO (R_MIPS_GOT_OFST,	/* type */
3902159047fSniklas 	 0,			/* rightshift */
3912159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3922159047fSniklas 	 16,			/* bitsize */
393c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
3942159047fSniklas 	 0,			/* bitpos */
395c074d1c9Sdrahn 	 complain_overflow_signed, /* complain_on_overflow */
396*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
3972159047fSniklas 	 "R_MIPS_GOT_OFST",	/* name */
398c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3992159047fSniklas 	 0x0000ffff,		/* src_mask */
4002159047fSniklas 	 0x0000ffff,		/* dst_mask */
401c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4022159047fSniklas 
4032159047fSniklas   /* High 16 bits of displacement in global offset table.  */
4042159047fSniklas   HOWTO (R_MIPS_GOT_HI16,	/* type */
4052159047fSniklas 	 0,			/* rightshift */
4062159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
4072159047fSniklas 	 16,			/* bitsize */
408c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
4092159047fSniklas 	 0,			/* bitpos */
4102159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
411*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
4122159047fSniklas 	 "R_MIPS_GOT_HI16",	/* name */
413c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
4142159047fSniklas 	 0x0000ffff,		/* src_mask */
4152159047fSniklas 	 0x0000ffff,		/* dst_mask */
416c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4172159047fSniklas 
4182159047fSniklas   /* Low 16 bits of displacement in global offset table.  */
4192159047fSniklas   HOWTO (R_MIPS_GOT_LO16,	/* type */
4202159047fSniklas 	 0,			/* rightshift */
4212159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
4222159047fSniklas 	 16,			/* bitsize */
423c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
4242159047fSniklas 	 0,			/* bitpos */
4252159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
426*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
4272159047fSniklas 	 "R_MIPS_GOT_LO16",	/* name */
428c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
4292159047fSniklas 	 0x0000ffff,		/* src_mask */
4302159047fSniklas 	 0x0000ffff,		/* dst_mask */
431c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4322159047fSniklas 
433b305b0f1Sespie   /* 64 bit subtraction.  Used in the N32 ABI.  */
434b305b0f1Sespie   HOWTO (R_MIPS_SUB,		/* type */
435b305b0f1Sespie 	 0,			/* rightshift */
436b305b0f1Sespie 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
437b305b0f1Sespie 	 64,			/* bitsize */
438c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
439b305b0f1Sespie 	 0,			/* bitpos */
440c074d1c9Sdrahn 	 complain_overflow_dont, /* complain_on_overflow */
441*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
442b305b0f1Sespie 	 "R_MIPS_SUB",		/* name */
443c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
444b305b0f1Sespie 	 MINUS_ONE,		/* src_mask */
445b305b0f1Sespie 	 MINUS_ONE,		/* dst_mask */
446c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4472159047fSniklas 
4482159047fSniklas   /* Used to cause the linker to insert and delete instructions?  */
449b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_INSERT_A),
450b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_INSERT_B),
451b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_DELETE),
4522159047fSniklas 
453b305b0f1Sespie   /* Get the higher value of a 64 bit addend.  */
454b305b0f1Sespie   HOWTO (R_MIPS_HIGHER,		/* type */
455b305b0f1Sespie 	 0,			/* rightshift */
456b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
457b305b0f1Sespie 	 16,			/* bitsize */
458c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
459b305b0f1Sespie 	 0,			/* bitpos */
460b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
461*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
462b305b0f1Sespie 	 "R_MIPS_HIGHER",	/* name */
463c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
464c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
465c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
466c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
467b305b0f1Sespie 
468b305b0f1Sespie   /* Get the highest value of a 64 bit addend.  */
469b305b0f1Sespie   HOWTO (R_MIPS_HIGHEST,	/* type */
470b305b0f1Sespie 	 0,			/* rightshift */
471b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
472b305b0f1Sespie 	 16,			/* bitsize */
473c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
474b305b0f1Sespie 	 0,			/* bitpos */
475b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
476*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
477b305b0f1Sespie 	 "R_MIPS_HIGHEST",	/* name */
478c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
479c074d1c9Sdrahn 	 0x0000ffff,		/* src_mask */
480c074d1c9Sdrahn 	 0x0000ffff,		/* dst_mask */
481c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4822159047fSniklas 
4832159047fSniklas   /* High 16 bits of displacement in global offset table.  */
4842159047fSniklas   HOWTO (R_MIPS_CALL_HI16,	/* type */
4852159047fSniklas 	 0,			/* rightshift */
4862159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
4872159047fSniklas 	 16,			/* bitsize */
488c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
4892159047fSniklas 	 0,			/* bitpos */
4902159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
491*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
4922159047fSniklas 	 "R_MIPS_CALL_HI16",	/* name */
493c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
4942159047fSniklas 	 0x0000ffff,		/* src_mask */
4952159047fSniklas 	 0x0000ffff,		/* dst_mask */
496c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
4972159047fSniklas 
4982159047fSniklas   /* Low 16 bits of displacement in global offset table.  */
4992159047fSniklas   HOWTO (R_MIPS_CALL_LO16,	/* type */
5002159047fSniklas 	 0,			/* rightshift */
5012159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
5022159047fSniklas 	 16,			/* bitsize */
503c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
5042159047fSniklas 	 0,			/* bitpos */
5052159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
506*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
5072159047fSniklas 	 "R_MIPS_CALL_LO16",	/* name */
508c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
5092159047fSniklas 	 0x0000ffff,		/* src_mask */
5102159047fSniklas 	 0x0000ffff,		/* dst_mask */
511c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
512b305b0f1Sespie 
513b305b0f1Sespie   /* Section displacement.  */
514b305b0f1Sespie   HOWTO (R_MIPS_SCN_DISP,       /* type */
515b305b0f1Sespie 	 0,			/* rightshift */
516b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
517b305b0f1Sespie 	 32,			/* bitsize */
518c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
519b305b0f1Sespie 	 0,			/* bitpos */
520b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
521*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
522b305b0f1Sespie 	 "R_MIPS_SCN_DISP",     /* name */
523c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
524b305b0f1Sespie 	 0xffffffff,		/* src_mask */
525b305b0f1Sespie 	 0xffffffff,		/* dst_mask */
526c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
527b305b0f1Sespie 
528b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_REL16),
529b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
530b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_PJUMP),
531b305b0f1Sespie   EMPTY_HOWTO (R_MIPS_RELGOT),
532b305b0f1Sespie 
533b305b0f1Sespie   /* Protected jump conversion.  This is an optimization hint.  No
534b305b0f1Sespie      relocation is required for correctness.  */
535b305b0f1Sespie   HOWTO (R_MIPS_JALR,	        /* type */
536b305b0f1Sespie 	 0,			/* rightshift */
537c074d1c9Sdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
538c074d1c9Sdrahn 	 32,			/* bitsize */
539c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
540b305b0f1Sespie 	 0,			/* bitpos */
541b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
542*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
543b305b0f1Sespie 	 "R_MIPS_JALR",	        /* name */
544c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
545b305b0f1Sespie 	 0x00000000,		/* src_mask */
546b305b0f1Sespie 	 0x00000000,		/* dst_mask */
547c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
5482159047fSniklas };
5492159047fSniklas 
550b305b0f1Sespie /* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link.  This
551b305b0f1Sespie    is a hack to make the linker think that we need 64 bit values.  */
552b305b0f1Sespie static reloc_howto_type elf_mips_ctor64_howto =
553b305b0f1Sespie   HOWTO (R_MIPS_64,		/* type */
554b305b0f1Sespie 	 0,			/* rightshift */
555b305b0f1Sespie 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
556b305b0f1Sespie 	 32,			/* bitsize */
557c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
558b305b0f1Sespie 	 0,			/* bitpos */
559b305b0f1Sespie 	 complain_overflow_signed, /* complain_on_overflow */
560b305b0f1Sespie 	 mips32_64bit_reloc,	/* special_function */
561b305b0f1Sespie 	 "R_MIPS_64",		/* name */
562c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
563b305b0f1Sespie 	 0xffffffff,		/* src_mask */
564b305b0f1Sespie 	 0xffffffff,		/* dst_mask */
565c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
566b305b0f1Sespie 
567b305b0f1Sespie /* The reloc used for the mips16 jump instruction.  */
568b305b0f1Sespie static reloc_howto_type elf_mips16_jump_howto =
569b305b0f1Sespie   HOWTO (R_MIPS16_26,		/* type */
570b305b0f1Sespie 	 2,			/* rightshift */
571b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
572b305b0f1Sespie 	 26,			/* bitsize */
573c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
574b305b0f1Sespie 	 0,			/* bitpos */
575b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
576b305b0f1Sespie 	 			/* This needs complex overflow
577b305b0f1Sespie 				   detection, because the upper four
578b305b0f1Sespie 				   bits must match the PC.  */
579b305b0f1Sespie 	 mips16_jump_reloc,	/* special_function */
580b305b0f1Sespie 	 "R_MIPS16_26",		/* name */
581c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
582b305b0f1Sespie 	 0x3ffffff,		/* src_mask */
583b305b0f1Sespie 	 0x3ffffff,		/* dst_mask */
584c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
585b305b0f1Sespie 
586b305b0f1Sespie /* The reloc used for the mips16 gprel instruction.  */
587b305b0f1Sespie static reloc_howto_type elf_mips16_gprel_howto =
588b305b0f1Sespie   HOWTO (R_MIPS16_GPREL,	/* type */
589b305b0f1Sespie 	 0,			/* rightshift */
590b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
591b305b0f1Sespie 	 16,			/* bitsize */
592c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
593b305b0f1Sespie 	 0,			/* bitpos */
594b305b0f1Sespie 	 complain_overflow_signed, /* complain_on_overflow */
595b305b0f1Sespie 	 mips16_gprel_reloc,	/* special_function */
596b305b0f1Sespie 	 "R_MIPS16_GPREL",	/* name */
597c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
598b305b0f1Sespie 	 0x07ff001f,		/* src_mask */
599b305b0f1Sespie 	 0x07ff001f,	        /* dst_mask */
600c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
601b305b0f1Sespie 
602b305b0f1Sespie /* GNU extensions for embedded-pic.  */
603b305b0f1Sespie /* High 16 bits of symbol value, pc-relative.  */
604b305b0f1Sespie static reloc_howto_type elf_mips_gnu_rel_hi16 =
605b305b0f1Sespie   HOWTO (R_MIPS_GNU_REL_HI16,	/* type */
606*007c2a45Smiod 	 16,			/* rightshift */
607b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
608b305b0f1Sespie 	 16,			/* bitsize */
609c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
610b305b0f1Sespie 	 0,			/* bitpos */
611b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
612*007c2a45Smiod 	 _bfd_mips_elf_hi16_reloc, /* special_function */
613b305b0f1Sespie 	 "R_MIPS_GNU_REL_HI16",	/* name */
614c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
615b305b0f1Sespie 	 0xffff,		/* src_mask */
616b305b0f1Sespie 	 0xffff,		/* dst_mask */
617c074d1c9Sdrahn 	 TRUE);			/* pcrel_offset */
618b305b0f1Sespie 
619b305b0f1Sespie /* Low 16 bits of symbol value, pc-relative.  */
620b305b0f1Sespie static reloc_howto_type elf_mips_gnu_rel_lo16 =
621b305b0f1Sespie   HOWTO (R_MIPS_GNU_REL_LO16,	/* type */
622b305b0f1Sespie 	 0,			/* rightshift */
623b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
624b305b0f1Sespie 	 16,			/* bitsize */
625c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
626b305b0f1Sespie 	 0,			/* bitpos */
627b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
628*007c2a45Smiod 	 _bfd_mips_elf_lo16_reloc, /* special_function */
629b305b0f1Sespie 	 "R_MIPS_GNU_REL_LO16",	/* name */
630c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
631b305b0f1Sespie 	 0xffff,		/* src_mask */
632b305b0f1Sespie 	 0xffff,		/* dst_mask */
633c074d1c9Sdrahn 	 TRUE);			/* pcrel_offset */
634b305b0f1Sespie 
635b305b0f1Sespie /* 16 bit offset for pc-relative branches.  */
636b305b0f1Sespie static reloc_howto_type elf_mips_gnu_rel16_s2 =
637b305b0f1Sespie   HOWTO (R_MIPS_GNU_REL16_S2,	/* type */
638b305b0f1Sespie 	 2,			/* rightshift */
639b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
640b305b0f1Sespie 	 16,			/* bitsize */
641c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
642b305b0f1Sespie 	 0,			/* bitpos */
643b305b0f1Sespie 	 complain_overflow_signed, /* complain_on_overflow */
644*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
645b305b0f1Sespie 	 "R_MIPS_GNU_REL16_S2",	/* name */
646c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
647b305b0f1Sespie 	 0xffff,		/* src_mask */
648b305b0f1Sespie 	 0xffff,		/* dst_mask */
649c074d1c9Sdrahn 	 TRUE);			/* pcrel_offset */
650b305b0f1Sespie 
651b305b0f1Sespie /* 64 bit pc-relative.  */
652b305b0f1Sespie static reloc_howto_type elf_mips_gnu_pcrel64 =
653b305b0f1Sespie   HOWTO (R_MIPS_PC64,		/* type */
654b305b0f1Sespie 	 0,			/* rightshift */
655b305b0f1Sespie 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
656b305b0f1Sespie 	 64,			/* bitsize */
657c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
658b305b0f1Sespie 	 0,			/* bitpos */
659b305b0f1Sespie 	 complain_overflow_signed, /* complain_on_overflow */
660*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
661b305b0f1Sespie 	 "R_MIPS_PC64",		/* name */
662c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
663b305b0f1Sespie 	 MINUS_ONE,		/* src_mask */
664b305b0f1Sespie 	 MINUS_ONE,		/* dst_mask */
665c074d1c9Sdrahn 	 TRUE);			/* pcrel_offset */
666b305b0f1Sespie 
667b305b0f1Sespie /* 32 bit pc-relative.  */
668b305b0f1Sespie static reloc_howto_type elf_mips_gnu_pcrel32 =
669b305b0f1Sespie   HOWTO (R_MIPS_PC32,		/* type */
670b305b0f1Sespie 	 0,			/* rightshift */
671b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
672b305b0f1Sespie 	 32,			/* bitsize */
673c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
674b305b0f1Sespie 	 0,			/* bitpos */
675b305b0f1Sespie 	 complain_overflow_signed, /* complain_on_overflow */
676*007c2a45Smiod 	 _bfd_mips_elf_generic_reloc, /* special_function */
677b305b0f1Sespie 	 "R_MIPS_PC32",		/* name */
678c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
679b305b0f1Sespie 	 0xffffffff,		/* src_mask */
680b305b0f1Sespie 	 0xffffffff,		/* dst_mask */
681c074d1c9Sdrahn 	 TRUE);			/* pcrel_offset */
682b305b0f1Sespie 
683b305b0f1Sespie /* GNU extension to record C++ vtable hierarchy */
684b305b0f1Sespie static reloc_howto_type elf_mips_gnu_vtinherit_howto =
685b305b0f1Sespie   HOWTO (R_MIPS_GNU_VTINHERIT,	/* type */
686b305b0f1Sespie 	 0,			/* rightshift */
687b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
688b305b0f1Sespie 	 0,			/* bitsize */
689c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
690b305b0f1Sespie 	 0,			/* bitpos */
691b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
692b305b0f1Sespie 	 NULL,			/* special_function */
693b305b0f1Sespie 	 "R_MIPS_GNU_VTINHERIT", /* name */
694c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
695b305b0f1Sespie 	 0,			/* src_mask */
696b305b0f1Sespie 	 0,			/* dst_mask */
697c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
698b305b0f1Sespie 
699b305b0f1Sespie /* GNU extension to record C++ vtable member usage */
700b305b0f1Sespie static reloc_howto_type elf_mips_gnu_vtentry_howto =
701b305b0f1Sespie   HOWTO (R_MIPS_GNU_VTENTRY,	/* type */
702b305b0f1Sespie 	 0,			/* rightshift */
703b305b0f1Sespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
704b305b0f1Sespie 	 0,			/* bitsize */
705c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
706b305b0f1Sespie 	 0,			/* bitpos */
707b305b0f1Sespie 	 complain_overflow_dont, /* complain_on_overflow */
708b305b0f1Sespie 	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
709b305b0f1Sespie 	 "R_MIPS_GNU_VTENTRY",	/* name */
710c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
711b305b0f1Sespie 	 0,			/* src_mask */
712b305b0f1Sespie 	 0,			/* dst_mask */
713c074d1c9Sdrahn 	 FALSE);		/* pcrel_offset */
714b305b0f1Sespie 
715c074d1c9Sdrahn /* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
716b305b0f1Sespie    dangerous relocation.  */
717b305b0f1Sespie 
718c074d1c9Sdrahn static bfd_boolean
mips_elf_assign_gp(bfd * output_bfd,bfd_vma * pgp)719*007c2a45Smiod mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
720b305b0f1Sespie {
721b305b0f1Sespie   unsigned int count;
722b305b0f1Sespie   asymbol **sym;
723b305b0f1Sespie   unsigned int i;
724b305b0f1Sespie 
725b305b0f1Sespie   /* If we've already figured out what GP will be, just return it.  */
726b305b0f1Sespie   *pgp = _bfd_get_gp_value (output_bfd);
727b305b0f1Sespie   if (*pgp)
728c074d1c9Sdrahn     return TRUE;
729b305b0f1Sespie 
730b305b0f1Sespie   count = bfd_get_symcount (output_bfd);
731b305b0f1Sespie   sym = bfd_get_outsymbols (output_bfd);
732b305b0f1Sespie 
733b305b0f1Sespie   /* The linker script will have created a symbol named `_gp' with the
734b305b0f1Sespie      appropriate value.  */
735*007c2a45Smiod   if (sym == NULL)
736b305b0f1Sespie     i = count;
737b305b0f1Sespie   else
738b305b0f1Sespie     {
739b305b0f1Sespie       for (i = 0; i < count; i++, sym++)
740b305b0f1Sespie 	{
741c074d1c9Sdrahn 	  register const char *name;
742b305b0f1Sespie 
743b305b0f1Sespie 	  name = bfd_asymbol_name (*sym);
744b305b0f1Sespie 	  if (*name == '_' && strcmp (name, "_gp") == 0)
745b305b0f1Sespie 	    {
746b305b0f1Sespie 	      *pgp = bfd_asymbol_value (*sym);
747b305b0f1Sespie 	      _bfd_set_gp_value (output_bfd, *pgp);
748b305b0f1Sespie 	      break;
749b305b0f1Sespie 	    }
750b305b0f1Sespie 	}
751b305b0f1Sespie     }
752b305b0f1Sespie 
753b305b0f1Sespie   if (i >= count)
754b305b0f1Sespie     {
755b305b0f1Sespie       /* Only get the error once.  */
756b305b0f1Sespie       *pgp = 4;
757b305b0f1Sespie       _bfd_set_gp_value (output_bfd, *pgp);
758c074d1c9Sdrahn       return FALSE;
759b305b0f1Sespie     }
760b305b0f1Sespie 
761c074d1c9Sdrahn   return TRUE;
762b305b0f1Sespie }
763b305b0f1Sespie 
7642159047fSniklas /* We have to figure out the gp value, so that we can adjust the
7652159047fSniklas    symbol value correctly.  We look up the symbol _gp in the output
7662159047fSniklas    BFD.  If we can't find it, we're stuck.  We cache it in the ELF
7672159047fSniklas    target data.  We don't need to adjust the symbol value for an
768*007c2a45Smiod    external symbol if we are producing relocatable output.  */
769c88b1d6cSniklas 
770c88b1d6cSniklas static bfd_reloc_status_type
mips_elf_final_gp(bfd * output_bfd,asymbol * symbol,bfd_boolean relocatable,char ** error_message,bfd_vma * pgp)771*007c2a45Smiod mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
772*007c2a45Smiod 		   char **error_message, bfd_vma *pgp)
773c88b1d6cSniklas {
774c88b1d6cSniklas   if (bfd_is_und_section (symbol->section)
775*007c2a45Smiod       && ! relocatable)
776c88b1d6cSniklas     {
777c88b1d6cSniklas       *pgp = 0;
778c88b1d6cSniklas       return bfd_reloc_undefined;
779c88b1d6cSniklas     }
780c88b1d6cSniklas 
781c88b1d6cSniklas   *pgp = _bfd_get_gp_value (output_bfd);
782c88b1d6cSniklas   if (*pgp == 0
783*007c2a45Smiod       && (! relocatable
7842159047fSniklas 	  || (symbol->flags & BSF_SECTION_SYM) != 0))
7852159047fSniklas     {
786*007c2a45Smiod       if (relocatable)
7872159047fSniklas 	{
7882159047fSniklas 	  /* Make up a value.  */
789c88b1d6cSniklas 	  *pgp = symbol->section->output_section->vma + 0x4000;
790c88b1d6cSniklas 	  _bfd_set_gp_value (output_bfd, *pgp);
7912159047fSniklas 	}
792b305b0f1Sespie       else if (!mips_elf_assign_gp (output_bfd, pgp))
7932159047fSniklas 	{
7942159047fSniklas 	  *error_message =
795b305b0f1Sespie 	    (char *) _("GP relative relocation when _gp not defined");
7962159047fSniklas 	  return bfd_reloc_dangerous;
7972159047fSniklas 	}
7982159047fSniklas     }
7992159047fSniklas 
800c88b1d6cSniklas   return bfd_reloc_ok;
801c88b1d6cSniklas }
802c88b1d6cSniklas 
803c88b1d6cSniklas /* Do a R_MIPS_GPREL16 relocation.  This is a 16 bit value which must
804c88b1d6cSniklas    become the offset from the gp register.  This function also handles
805c88b1d6cSniklas    R_MIPS_LITERAL relocations, although those can be handled more
806c88b1d6cSniklas    cleverly because the entries in the .lit8 and .lit4 sections can be
807c88b1d6cSniklas    merged.  */
808c88b1d6cSniklas 
809c88b1d6cSniklas bfd_reloc_status_type
_bfd_mips_elf32_gprel16_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)810*007c2a45Smiod _bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry,
811*007c2a45Smiod 			       asymbol *symbol, void *data,
812*007c2a45Smiod 			       asection *input_section, bfd *output_bfd,
813*007c2a45Smiod 			       char **error_message)
814c88b1d6cSniklas {
815*007c2a45Smiod   bfd_boolean relocatable;
816c88b1d6cSniklas   bfd_reloc_status_type ret;
817c88b1d6cSniklas   bfd_vma gp;
818c88b1d6cSniklas 
819*007c2a45Smiod   if (output_bfd != NULL)
820*007c2a45Smiod     relocatable = TRUE;
821c88b1d6cSniklas   else
822c88b1d6cSniklas     {
823*007c2a45Smiod       relocatable = FALSE;
824c88b1d6cSniklas       output_bfd = symbol->section->output_section->owner;
825c88b1d6cSniklas     }
826c88b1d6cSniklas 
827*007c2a45Smiod   ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
828c88b1d6cSniklas 			   &gp);
829c88b1d6cSniklas   if (ret != bfd_reloc_ok)
830c88b1d6cSniklas     return ret;
831c88b1d6cSniklas 
832c074d1c9Sdrahn   return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
833*007c2a45Smiod 					input_section, relocatable,
834c074d1c9Sdrahn 					data, gp);
8352159047fSniklas }
8362159047fSniklas 
837c074d1c9Sdrahn /* Do a R_MIPS_GPREL32 relocation.  This is a 32 bit value which must
838c074d1c9Sdrahn    become the offset from the gp register.  */
839c074d1c9Sdrahn 
8402159047fSniklas static bfd_reloc_status_type
mips_elf_gprel32_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)841*007c2a45Smiod mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
842*007c2a45Smiod 			void *data, asection *input_section, bfd *output_bfd,
843*007c2a45Smiod 			char **error_message)
844c88b1d6cSniklas {
845*007c2a45Smiod   bfd_boolean relocatable;
846c88b1d6cSniklas   bfd_reloc_status_type ret;
847c88b1d6cSniklas   bfd_vma gp;
848c88b1d6cSniklas 
849*007c2a45Smiod   if (output_bfd != NULL)
850*007c2a45Smiod     relocatable = TRUE;
851c88b1d6cSniklas   else
852c88b1d6cSniklas     {
853*007c2a45Smiod       relocatable = FALSE;
854c88b1d6cSniklas       output_bfd = symbol->section->output_section->owner;
855*007c2a45Smiod     }
856c88b1d6cSniklas 
857*007c2a45Smiod   ret = mips_elf_final_gp (output_bfd, symbol, relocatable,
858c88b1d6cSniklas 			   error_message, &gp);
859c88b1d6cSniklas   if (ret != bfd_reloc_ok)
860c88b1d6cSniklas     return ret;
861c88b1d6cSniklas 
862c88b1d6cSniklas   return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
863*007c2a45Smiod 			  relocatable, data, gp);
864c88b1d6cSniklas }
865c88b1d6cSniklas 
866c88b1d6cSniklas static bfd_reloc_status_type
gprel32_with_gp(bfd * abfd,asymbol * symbol,arelent * reloc_entry,asection * input_section,bfd_boolean relocatable,void * data,bfd_vma gp)867*007c2a45Smiod gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
868*007c2a45Smiod 		 asection *input_section, bfd_boolean relocatable,
869*007c2a45Smiod 		 void *data, bfd_vma gp)
870c88b1d6cSniklas {
871c88b1d6cSniklas   bfd_vma relocation;
872*007c2a45Smiod   bfd_vma val;
873c88b1d6cSniklas 
874c88b1d6cSniklas   if (bfd_is_com_section (symbol->section))
875c88b1d6cSniklas     relocation = 0;
876c88b1d6cSniklas   else
877c88b1d6cSniklas     relocation = symbol->value;
878c88b1d6cSniklas 
879c88b1d6cSniklas   relocation += symbol->section->output_section->vma;
880c88b1d6cSniklas   relocation += symbol->section->output_offset;
881c88b1d6cSniklas 
882c88b1d6cSniklas   if (reloc_entry->address > input_section->_cooked_size)
883c88b1d6cSniklas     return bfd_reloc_outofrange;
884c88b1d6cSniklas 
885c88b1d6cSniklas   /* Set val to the offset into the section or symbol.  */
886*007c2a45Smiod   val = reloc_entry->addend;
887*007c2a45Smiod 
888*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
889*007c2a45Smiod     val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
890c88b1d6cSniklas 
891c88b1d6cSniklas   /* Adjust val for the final section location and GP value.  If we
892*007c2a45Smiod      are producing relocatable output, we don't want to do this for
893c88b1d6cSniklas      an external symbol.  */
894*007c2a45Smiod   if (! relocatable
895c88b1d6cSniklas       || (symbol->flags & BSF_SECTION_SYM) != 0)
896c88b1d6cSniklas     val += relocation - gp;
897c88b1d6cSniklas 
898*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
899*007c2a45Smiod     bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
900*007c2a45Smiod   else
901*007c2a45Smiod     reloc_entry->addend = val;
902c88b1d6cSniklas 
903*007c2a45Smiod   if (relocatable)
904c88b1d6cSniklas     reloc_entry->address += input_section->output_offset;
905c88b1d6cSniklas 
906c88b1d6cSniklas   return bfd_reloc_ok;
907c88b1d6cSniklas }
908c88b1d6cSniklas 
909e93f7393Sniklas /* Handle a 64 bit reloc in a 32 bit MIPS ELF file.  These are
910b55d4692Sfgsch    generated when addresses are 64 bits.  The upper 32 bits are a simple
911e93f7393Sniklas    sign extension.  */
912e93f7393Sniklas 
913e93f7393Sniklas static bfd_reloc_status_type
mips32_64bit_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol ATTRIBUTE_UNUSED,void * data,asection * input_section,bfd * output_bfd,char ** error_message)914*007c2a45Smiod mips32_64bit_reloc (bfd *abfd, arelent *reloc_entry,
915*007c2a45Smiod 		    asymbol *symbol ATTRIBUTE_UNUSED,
916*007c2a45Smiod 		    void *data, asection *input_section,
917*007c2a45Smiod 		    bfd *output_bfd, char **error_message)
918e93f7393Sniklas {
919e93f7393Sniklas   bfd_reloc_status_type r;
920e93f7393Sniklas   arelent reloc32;
921e93f7393Sniklas   unsigned long val;
922e93f7393Sniklas   bfd_size_type addr;
923e93f7393Sniklas 
924e93f7393Sniklas   /* Do a normal 32 bit relocation on the lower 32 bits.  */
925e93f7393Sniklas   reloc32 = *reloc_entry;
926e93f7393Sniklas   if (bfd_big_endian (abfd))
927e93f7393Sniklas     reloc32.address += 4;
928c074d1c9Sdrahn   reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32];
929e93f7393Sniklas   r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
930e93f7393Sniklas 			      output_bfd, error_message);
931e93f7393Sniklas 
932e93f7393Sniklas   /* Sign extend into the upper 32 bits.  */
933e93f7393Sniklas   val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address);
934e93f7393Sniklas   if ((val & 0x80000000) != 0)
935e93f7393Sniklas     val = 0xffffffff;
936e93f7393Sniklas   else
937e93f7393Sniklas     val = 0;
938e93f7393Sniklas   addr = reloc_entry->address;
939e93f7393Sniklas   if (bfd_little_endian (abfd))
940e93f7393Sniklas     addr += 4;
941*007c2a45Smiod   bfd_put_32 (abfd, val, (bfd_byte *) data + addr);
942e93f7393Sniklas 
943e93f7393Sniklas   return r;
944e93f7393Sniklas }
945e93f7393Sniklas 
946b305b0f1Sespie /* Handle a mips16 jump.  */
947b305b0f1Sespie 
948b305b0f1Sespie 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)949*007c2a45Smiod mips16_jump_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
950*007c2a45Smiod 		   asymbol *symbol, void *data ATTRIBUTE_UNUSED,
951*007c2a45Smiod 		   asection *input_section, bfd *output_bfd,
952*007c2a45Smiod 		   char **error_message ATTRIBUTE_UNUSED)
953b305b0f1Sespie {
954*007c2a45Smiod   if (output_bfd != NULL
955b305b0f1Sespie       && (symbol->flags & BSF_SECTION_SYM) == 0
956b305b0f1Sespie       && reloc_entry->addend == 0)
957b305b0f1Sespie     {
958b305b0f1Sespie       reloc_entry->address += input_section->output_offset;
959b305b0f1Sespie       return bfd_reloc_ok;
960b305b0f1Sespie     }
961b305b0f1Sespie 
962b305b0f1Sespie   /* FIXME.  */
963b305b0f1Sespie   {
964c074d1c9Sdrahn     static bfd_boolean warned;
965b305b0f1Sespie 
966b305b0f1Sespie     if (! warned)
967b305b0f1Sespie       (*_bfd_error_handler)
968b305b0f1Sespie 	(_("Linking mips16 objects into %s format is not supported"),
969b305b0f1Sespie 	 bfd_get_target (input_section->output_section->owner));
970c074d1c9Sdrahn     warned = TRUE;
971b305b0f1Sespie   }
972b305b0f1Sespie 
973b305b0f1Sespie   return bfd_reloc_undefined;
974b305b0f1Sespie }
975b305b0f1Sespie 
976b305b0f1Sespie /* Handle a mips16 GP relative reloc.  */
977b305b0f1Sespie 
978b305b0f1Sespie 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)979*007c2a45Smiod mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
980*007c2a45Smiod 		    void *data, asection *input_section, bfd *output_bfd,
981*007c2a45Smiod 		    char **error_message)
982b305b0f1Sespie {
983*007c2a45Smiod   bfd_boolean relocatable;
984b305b0f1Sespie   bfd_reloc_status_type ret;
985b305b0f1Sespie   bfd_vma gp;
986*007c2a45Smiod   unsigned short extend = 0;
987*007c2a45Smiod   unsigned short insn = 0;
988*007c2a45Smiod   bfd_signed_vma val;
989*007c2a45Smiod   bfd_vma relocation;
990b305b0f1Sespie 
991*007c2a45Smiod   /* If we're relocating, and this is an external symbol, we don't want
992*007c2a45Smiod      to change anything.  */
993b305b0f1Sespie   if (output_bfd != NULL
994b305b0f1Sespie       && (symbol->flags & BSF_SECTION_SYM) == 0
995*007c2a45Smiod       && (symbol->flags & BSF_LOCAL) != 0)
996b305b0f1Sespie     {
997b305b0f1Sespie       reloc_entry->address += input_section->output_offset;
998b305b0f1Sespie       return bfd_reloc_ok;
999b305b0f1Sespie     }
1000b305b0f1Sespie 
1001b305b0f1Sespie   if (output_bfd != NULL)
1002*007c2a45Smiod     relocatable = TRUE;
1003b305b0f1Sespie   else
1004b305b0f1Sespie     {
1005*007c2a45Smiod       relocatable = FALSE;
1006b305b0f1Sespie       output_bfd = symbol->section->output_section->owner;
1007b305b0f1Sespie     }
1008b305b0f1Sespie 
1009*007c2a45Smiod   ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
1010b305b0f1Sespie 			   &gp);
1011b305b0f1Sespie   if (ret != bfd_reloc_ok)
1012b305b0f1Sespie     return ret;
1013b305b0f1Sespie 
1014b305b0f1Sespie   if (reloc_entry->address > input_section->_cooked_size)
1015b305b0f1Sespie     return bfd_reloc_outofrange;
1016b305b0f1Sespie 
1017*007c2a45Smiod   if (bfd_is_com_section (symbol->section))
1018*007c2a45Smiod     relocation = 0;
1019*007c2a45Smiod   else
1020*007c2a45Smiod     relocation = symbol->value;
1021*007c2a45Smiod 
1022*007c2a45Smiod   relocation += symbol->section->output_section->vma;
1023*007c2a45Smiod   relocation += symbol->section->output_offset;
1024*007c2a45Smiod 
1025*007c2a45Smiod   /* Set val to the offset into the section or symbol.  */
1026*007c2a45Smiod   val = reloc_entry->addend;
1027*007c2a45Smiod 
1028*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1029*007c2a45Smiod     {
1030b305b0f1Sespie       /* Pick up the mips16 extend instruction and the real instruction.  */
1031b305b0f1Sespie       extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
1032b305b0f1Sespie       insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
1033*007c2a45Smiod       val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
1034*007c2a45Smiod     }
1035b305b0f1Sespie 
1036*007c2a45Smiod   _bfd_mips_elf_sign_extend(val, 16);
1037b305b0f1Sespie 
1038*007c2a45Smiod   /* Adjust val for the final section location and GP value.  If we
1039*007c2a45Smiod      are producing relocatable output, we don't want to do this for
1040*007c2a45Smiod      an external symbol.  */
1041*007c2a45Smiod   if (! relocatable
1042*007c2a45Smiod       || (symbol->flags & BSF_SECTION_SYM) != 0)
1043*007c2a45Smiod     val += relocation - gp;
1044b305b0f1Sespie 
1045*007c2a45Smiod   if (reloc_entry->howto->partial_inplace)
1046*007c2a45Smiod     {
1047b305b0f1Sespie       bfd_put_16 (abfd,
1048*007c2a45Smiod 		  (extend & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0),
1049b305b0f1Sespie 		  (bfd_byte *) data + reloc_entry->address);
1050b305b0f1Sespie       bfd_put_16 (abfd,
1051*007c2a45Smiod 		  (insn & 0xffe0) | (val & 0x1f),
1052b305b0f1Sespie 		  (bfd_byte *) data + reloc_entry->address + 2);
1053*007c2a45Smiod     }
1054*007c2a45Smiod   else
1055*007c2a45Smiod     reloc_entry->addend = val;
1056b305b0f1Sespie 
1057*007c2a45Smiod   if (relocatable)
1058*007c2a45Smiod     reloc_entry->address += input_section->output_offset;
1059*007c2a45Smiod   else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0))
1060*007c2a45Smiod     return bfd_reloc_overflow;
1061*007c2a45Smiod 
1062*007c2a45Smiod   return bfd_reloc_ok;
1063b305b0f1Sespie }
1064b305b0f1Sespie 
10652159047fSniklas /* A mapping from BFD reloc types to MIPS ELF reloc types.  */
10662159047fSniklas 
10672159047fSniklas struct elf_reloc_map {
1068c074d1c9Sdrahn   bfd_reloc_code_real_type bfd_val;
1069c074d1c9Sdrahn   enum elf_mips_reloc_type elf_val;
10702159047fSniklas };
10712159047fSniklas 
1072c074d1c9Sdrahn static const struct elf_reloc_map mips_reloc_map[] =
10732159047fSniklas {
1074c074d1c9Sdrahn   { BFD_RELOC_NONE, R_MIPS_NONE },
10752159047fSniklas   { BFD_RELOC_16, R_MIPS_16 },
10762159047fSniklas   { BFD_RELOC_32, R_MIPS_32 },
1077c074d1c9Sdrahn   /* There is no BFD reloc for R_MIPS_REL32.  */
1078e93f7393Sniklas   { BFD_RELOC_64, R_MIPS_64 },
10792159047fSniklas   { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
10802159047fSniklas   { BFD_RELOC_HI16_S, R_MIPS_HI16 },
10812159047fSniklas   { BFD_RELOC_LO16, R_MIPS_LO16 },
1082c074d1c9Sdrahn   { BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
10832159047fSniklas   { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
10842159047fSniklas   { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
10852159047fSniklas   { BFD_RELOC_16_PCREL, R_MIPS_PC16 },
10862159047fSniklas   { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
1087c074d1c9Sdrahn   { BFD_RELOC_GPREL32, R_MIPS_GPREL32 },
1088c88b1d6cSniklas   { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
1089c88b1d6cSniklas   { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
1090c88b1d6cSniklas   { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
1091b305b0f1Sespie   { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 },
1092b305b0f1Sespie   { BFD_RELOC_MIPS_SUB, R_MIPS_SUB },
1093b305b0f1Sespie   { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE },
1094b305b0f1Sespie   { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST },
1095b305b0f1Sespie   { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }
10962159047fSniklas };
10972159047fSniklas 
10982159047fSniklas /* Given a BFD reloc type, return a howto structure.  */
10992159047fSniklas 
11002159047fSniklas static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup(bfd * abfd,bfd_reloc_code_real_type code)1101*007c2a45Smiod bfd_elf32_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
11022159047fSniklas {
11032159047fSniklas   unsigned int i;
1104c074d1c9Sdrahn   reloc_howto_type *howto_table = elf_mips_howto_table_rel;
11052159047fSniklas 
1106c074d1c9Sdrahn   for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
1107c074d1c9Sdrahn        i++)
11082159047fSniklas     {
1109c074d1c9Sdrahn       if (mips_reloc_map[i].bfd_val == code)
1110c074d1c9Sdrahn 	return &howto_table[(int) mips_reloc_map[i].elf_val];
11112159047fSniklas     }
1112b305b0f1Sespie 
1113b305b0f1Sespie   switch (code)
1114b305b0f1Sespie     {
1115b305b0f1Sespie     default:
1116b305b0f1Sespie       bfd_set_error (bfd_error_bad_value);
11172159047fSniklas       return NULL;
1118b305b0f1Sespie 
1119b305b0f1Sespie     case BFD_RELOC_CTOR:
1120b305b0f1Sespie       /* We need to handle BFD_RELOC_CTOR specially.
1121b305b0f1Sespie 	 Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
1122c074d1c9Sdrahn 	 size of addresses of the ABI.  */
1123c074d1c9Sdrahn       if ((elf_elfheader (abfd)->e_flags & (E_MIPS_ABI_O64
1124c074d1c9Sdrahn 					    | E_MIPS_ABI_EABI64)) != 0)
1125b305b0f1Sespie 	return &elf_mips_ctor64_howto;
1126c074d1c9Sdrahn       else
1127c074d1c9Sdrahn 	return &howto_table[(int) R_MIPS_32];
1128b305b0f1Sespie 
1129b305b0f1Sespie     case BFD_RELOC_MIPS16_JMP:
1130b305b0f1Sespie       return &elf_mips16_jump_howto;
1131b305b0f1Sespie     case BFD_RELOC_MIPS16_GPREL:
1132b305b0f1Sespie       return &elf_mips16_gprel_howto;
1133b305b0f1Sespie     case BFD_RELOC_VTABLE_INHERIT:
1134b305b0f1Sespie       return &elf_mips_gnu_vtinherit_howto;
1135b305b0f1Sespie     case BFD_RELOC_VTABLE_ENTRY:
1136b305b0f1Sespie       return &elf_mips_gnu_vtentry_howto;
1137b305b0f1Sespie     case BFD_RELOC_PCREL_HI16_S:
1138b305b0f1Sespie       return &elf_mips_gnu_rel_hi16;
1139b305b0f1Sespie     case BFD_RELOC_PCREL_LO16:
1140b305b0f1Sespie       return &elf_mips_gnu_rel_lo16;
1141b305b0f1Sespie     case BFD_RELOC_16_PCREL_S2:
1142b305b0f1Sespie       return &elf_mips_gnu_rel16_s2;
1143b305b0f1Sespie     case BFD_RELOC_64_PCREL:
1144b305b0f1Sespie       return &elf_mips_gnu_pcrel64;
1145b305b0f1Sespie     case BFD_RELOC_32_PCREL:
1146b305b0f1Sespie       return &elf_mips_gnu_pcrel32;
1147b305b0f1Sespie     }
11482159047fSniklas }
11492159047fSniklas 
1150c074d1c9Sdrahn /* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
1151b305b0f1Sespie 
1152b305b0f1Sespie static reloc_howto_type *
mips_elf32_rtype_to_howto(unsigned int r_type,bfd_boolean rela_p ATTRIBUTE_UNUSED)1153*007c2a45Smiod mips_elf32_rtype_to_howto (unsigned int r_type,
1154*007c2a45Smiod 			   bfd_boolean rela_p ATTRIBUTE_UNUSED)
1155b305b0f1Sespie {
1156b305b0f1Sespie   switch (r_type)
1157b305b0f1Sespie     {
1158b305b0f1Sespie     case R_MIPS16_26:
1159b305b0f1Sespie       return &elf_mips16_jump_howto;
1160b305b0f1Sespie     case R_MIPS16_GPREL:
1161b305b0f1Sespie       return &elf_mips16_gprel_howto;
1162b305b0f1Sespie     case R_MIPS_GNU_VTINHERIT:
1163b305b0f1Sespie       return &elf_mips_gnu_vtinherit_howto;
1164b305b0f1Sespie     case R_MIPS_GNU_VTENTRY:
1165b305b0f1Sespie       return &elf_mips_gnu_vtentry_howto;
1166b305b0f1Sespie     case R_MIPS_GNU_REL_HI16:
1167b305b0f1Sespie       return &elf_mips_gnu_rel_hi16;
1168b305b0f1Sespie     case R_MIPS_GNU_REL_LO16:
1169b305b0f1Sespie       return &elf_mips_gnu_rel_lo16;
1170b305b0f1Sespie     case R_MIPS_GNU_REL16_S2:
1171b305b0f1Sespie       return &elf_mips_gnu_rel16_s2;
1172b305b0f1Sespie     case R_MIPS_PC64:
1173b305b0f1Sespie       return &elf_mips_gnu_pcrel64;
1174b305b0f1Sespie     case R_MIPS_PC32:
1175b305b0f1Sespie       return &elf_mips_gnu_pcrel32;
1176b305b0f1Sespie     default:
1177b305b0f1Sespie       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
1178c074d1c9Sdrahn       return &elf_mips_howto_table_rel[r_type];
1179b305b0f1Sespie     }
1180b305b0f1Sespie }
1181b305b0f1Sespie 
1182c074d1c9Sdrahn /* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
11832159047fSniklas 
11842159047fSniklas static void
mips_info_to_howto_rel(bfd * abfd,arelent * cache_ptr,Elf_Internal_Rela * dst)1185*007c2a45Smiod mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
11862159047fSniklas {
11872159047fSniklas   unsigned int r_type;
11882159047fSniklas 
11892159047fSniklas   r_type = ELF32_R_TYPE (dst->r_info);
1190c074d1c9Sdrahn   cache_ptr->howto = mips_elf32_rtype_to_howto (r_type, FALSE);
11912159047fSniklas 
11922159047fSniklas   /* The addend for a GPREL16 or LITERAL relocation comes from the GP
11932159047fSniklas      value for the object file.  We get the addend now, rather than
11942159047fSniklas      when we do the relocation, because the symbol manipulations done
11952159047fSniklas      by the linker may cause us to lose track of the input BFD.  */
11962159047fSniklas   if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
11972159047fSniklas       && (r_type == (unsigned int) R_MIPS_GPREL16
11982159047fSniklas 	  || r_type == (unsigned int) R_MIPS_LITERAL))
11992159047fSniklas     cache_ptr->addend = elf_gp (abfd);
12002159047fSniklas }
1201b305b0f1Sespie 
1202c074d1c9Sdrahn /* Given a MIPS Elf_Internal_Rela, fill in an arelent structure.  */
1203b305b0f1Sespie 
1204b305b0f1Sespie static void
mips_info_to_howto_rela(bfd * abfd,arelent * cache_ptr,Elf_Internal_Rela * dst)1205*007c2a45Smiod mips_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
1206b305b0f1Sespie {
1207c074d1c9Sdrahn   mips_info_to_howto_rel (abfd, cache_ptr, dst);
1208b305b0f1Sespie 
1209b305b0f1Sespie   /* If we ever need to do any extra processing with dst->r_addend
1210c074d1c9Sdrahn      (the field omitted in an Elf_Internal_Rel) we can do it here.  */
1211b305b0f1Sespie }
12122159047fSniklas 
12132159047fSniklas /* Determine whether a symbol is global for the purposes of splitting
12142159047fSniklas    the symbol table into global symbols and local symbols.  At least
12152159047fSniklas    on Irix 5, this split must be between section symbols and all other
12162159047fSniklas    symbols.  On most ELF targets the split is between static symbols
12172159047fSniklas    and externally visible symbols.  */
12182159047fSniklas 
1219c074d1c9Sdrahn static bfd_boolean
mips_elf_sym_is_global(bfd * abfd ATTRIBUTE_UNUSED,asymbol * sym)1220*007c2a45Smiod mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
12212159047fSniklas {
1222b55d4692Sfgsch   if (SGI_COMPAT (abfd))
1223c074d1c9Sdrahn     return (sym->flags & BSF_SECTION_SYM) == 0;
1224b55d4692Sfgsch   else
1225b55d4692Sfgsch     return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
1226b55d4692Sfgsch 	    || bfd_is_und_section (bfd_get_section (sym))
1227b55d4692Sfgsch 	    || bfd_is_com_section (bfd_get_section (sym)));
12282159047fSniklas }
12292159047fSniklas 
1230c074d1c9Sdrahn /* Set the right machine number for a MIPS ELF file.  */
12312159047fSniklas 
1232c074d1c9Sdrahn static bfd_boolean
mips_elf32_object_p(bfd * abfd)1233*007c2a45Smiod mips_elf32_object_p (bfd *abfd)
12342159047fSniklas {
1235c074d1c9Sdrahn   unsigned long mach;
1236c074d1c9Sdrahn 
1237c074d1c9Sdrahn   /* Irix 5 and 6 are broken.  Object file symbol tables are not always
12382159047fSniklas      sorted correctly such that local symbols precede global symbols,
12392159047fSniklas      and the sh_info field in the symbol table is not always right.  */
1240b55d4692Sfgsch   if (SGI_COMPAT (abfd))
1241c074d1c9Sdrahn     elf_bad_symtab (abfd) = TRUE;
1242b305b0f1Sespie 
1243c074d1c9Sdrahn   if (ABI_N32_P (abfd))
1244c074d1c9Sdrahn     return FALSE;
1245b305b0f1Sespie 
1246c074d1c9Sdrahn   mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags);
1247c074d1c9Sdrahn   bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach);
12482159047fSniklas 
1249c074d1c9Sdrahn   return TRUE;
12502159047fSniklas }
12512159047fSniklas 
12522159047fSniklas /* MIPS ELF local labels start with '$', not 'L'.  */
12532159047fSniklas 
1254c074d1c9Sdrahn static bfd_boolean
mips_elf_is_local_label_name(bfd * abfd,const char * name)1255*007c2a45Smiod mips_elf_is_local_label_name (bfd *abfd, const char *name)
12562159047fSniklas {
1257b305b0f1Sespie   if (name[0] == '$')
1258c074d1c9Sdrahn     return TRUE;
1259b305b0f1Sespie 
1260b305b0f1Sespie   /* On Irix 6, the labels go back to starting with '.', so we accept
1261b305b0f1Sespie      the generic ELF local label syntax as well.  */
1262b305b0f1Sespie   return _bfd_elf_is_local_label_name (abfd, name);
12632159047fSniklas }
1264c074d1c9Sdrahn 
1265c074d1c9Sdrahn /* Support for core dump NOTE sections.  */
1266c074d1c9Sdrahn static bfd_boolean
elf32_mips_grok_prstatus(bfd * abfd,Elf_Internal_Note * note)1267*007c2a45Smiod elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
12682159047fSniklas {
1269c074d1c9Sdrahn   int offset;
1270c074d1c9Sdrahn   unsigned int raw_size;
12712159047fSniklas 
1272c074d1c9Sdrahn   switch (note->descsz)
12732159047fSniklas     {
1274c074d1c9Sdrahn       default:
1275c074d1c9Sdrahn 	return FALSE;
12762159047fSniklas 
1277c074d1c9Sdrahn       case 256:		/* Linux/MIPS */
1278c074d1c9Sdrahn 	/* pr_cursig */
1279c074d1c9Sdrahn 	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
12802159047fSniklas 
1281c074d1c9Sdrahn 	/* pr_pid */
1282c074d1c9Sdrahn 	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
12832159047fSniklas 
1284c074d1c9Sdrahn 	/* pr_reg */
1285c074d1c9Sdrahn 	offset = 72;
1286c074d1c9Sdrahn 	raw_size = 180;
1287c074d1c9Sdrahn 
1288c074d1c9Sdrahn 	break;
12892159047fSniklas     }
12902159047fSniklas 
1291c074d1c9Sdrahn   /* Make a ".reg/999" section.  */
1292c074d1c9Sdrahn   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
1293c074d1c9Sdrahn 					  raw_size, note->descpos + offset);
1294c074d1c9Sdrahn }
1295c074d1c9Sdrahn 
1296c074d1c9Sdrahn static bfd_boolean
elf32_mips_grok_psinfo(bfd * abfd,Elf_Internal_Note * note)1297*007c2a45Smiod elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
12982159047fSniklas {
1299c074d1c9Sdrahn   switch (note->descsz)
13002159047fSniklas     {
1301c074d1c9Sdrahn       default:
1302c074d1c9Sdrahn 	return FALSE;
13032159047fSniklas 
1304c074d1c9Sdrahn       case 128:		/* Linux/MIPS elf_prpsinfo */
1305c074d1c9Sdrahn 	elf_tdata (abfd)->core_program
1306c074d1c9Sdrahn 	 = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
1307c074d1c9Sdrahn 	elf_tdata (abfd)->core_command
1308c074d1c9Sdrahn 	 = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
13092159047fSniklas     }
13102159047fSniklas 
1311c074d1c9Sdrahn   /* Note that for some reason, a spurious space is tacked
1312c074d1c9Sdrahn      onto the end of the args in some (at least one anyway)
1313c074d1c9Sdrahn      implementations, so strip it off if it exists.  */
1314c074d1c9Sdrahn 
13152159047fSniklas   {
1316c074d1c9Sdrahn     char *command = elf_tdata (abfd)->core_command;
1317c074d1c9Sdrahn     int n = strlen (command);
1318c074d1c9Sdrahn 
1319c074d1c9Sdrahn     if (0 < n && command[n - 1] == ' ')
1320c074d1c9Sdrahn       command[n - 1] = '\0';
13212159047fSniklas   }
13222159047fSniklas 
1323c074d1c9Sdrahn   return TRUE;
13242159047fSniklas }
13252159047fSniklas 
1326c074d1c9Sdrahn /* Depending on the target vector we generate some version of Irix
1327c074d1c9Sdrahn    executables or "normal" MIPS ELF ABI executables.  */
1328c074d1c9Sdrahn static irix_compat_t
elf32_mips_irix_compat(bfd * abfd)1329*007c2a45Smiod elf32_mips_irix_compat (bfd *abfd)
13302159047fSniklas {
1331c074d1c9Sdrahn   if ((abfd->xvec == &bfd_elf32_bigmips_vec)
1332c074d1c9Sdrahn       || (abfd->xvec == &bfd_elf32_littlemips_vec))
1333c074d1c9Sdrahn     return ict_irix5;
13342159047fSniklas   else
1335c074d1c9Sdrahn     return ict_none;
13362159047fSniklas }
13372159047fSniklas 
1338c074d1c9Sdrahn /* Given a data section and an in-memory embedded reloc section, store
1339c074d1c9Sdrahn    relocation information into the embedded reloc section which can be
1340c074d1c9Sdrahn    used at runtime to relocate the data section.  This is called by the
1341c074d1c9Sdrahn    linker when the --embedded-relocs switch is used.  This is called
1342c074d1c9Sdrahn    after the add_symbols entry point has been called for all the
1343c074d1c9Sdrahn    objects, and before the final_link entry point is called.  */
1344c88b1d6cSniklas 
1345c074d1c9Sdrahn bfd_boolean
bfd_mips_elf32_create_embedded_relocs(bfd * abfd,struct bfd_link_info * info,asection * datasec,asection * relsec,char ** errmsg)1346*007c2a45Smiod bfd_mips_elf32_create_embedded_relocs (bfd *abfd, struct bfd_link_info *info,
1347*007c2a45Smiod 				       asection *datasec, asection *relsec,
1348*007c2a45Smiod 				       char **errmsg)
1349c88b1d6cSniklas {
1350c88b1d6cSniklas   Elf_Internal_Shdr *symtab_hdr;
1351c074d1c9Sdrahn   Elf_Internal_Sym *isymbuf = NULL;
1352c074d1c9Sdrahn   Elf_Internal_Rela *internal_relocs = NULL;
1353c074d1c9Sdrahn   Elf_Internal_Rela *irel, *irelend;
1354c88b1d6cSniklas   bfd_byte *p;
1355c88b1d6cSniklas 
1356*007c2a45Smiod   BFD_ASSERT (! info->relocatable);
1357c88b1d6cSniklas 
1358c074d1c9Sdrahn   *errmsg = NULL;
1359c88b1d6cSniklas 
1360c074d1c9Sdrahn   if (datasec->reloc_count == 0)
1361c074d1c9Sdrahn     return TRUE;
1362c88b1d6cSniklas 
1363c074d1c9Sdrahn   /* Read this BFD's symbols if we haven't done so already, or get the cached
1364c074d1c9Sdrahn      copy if it exists.  */
1365c074d1c9Sdrahn   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1366c074d1c9Sdrahn   if (symtab_hdr->sh_info != 0)
1367c88b1d6cSniklas     {
1368c074d1c9Sdrahn       isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1369c074d1c9Sdrahn       if (isymbuf == NULL)
1370c074d1c9Sdrahn 	isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1371c074d1c9Sdrahn 					symtab_hdr->sh_info, 0,
1372c074d1c9Sdrahn 					NULL, NULL, NULL);
1373c074d1c9Sdrahn       if (isymbuf == NULL)
1374c074d1c9Sdrahn 	goto error_return;
1375c88b1d6cSniklas     }
1376b305b0f1Sespie 
1377c074d1c9Sdrahn   /* Get a copy of the native relocations.  */
1378*007c2a45Smiod   internal_relocs = _bfd_elf_link_read_relocs (abfd, datasec, NULL, NULL,
1379*007c2a45Smiod 					       info->keep_memory);
1380c074d1c9Sdrahn   if (internal_relocs == NULL)
13812159047fSniklas     goto error_return;
13822159047fSniklas 
1383*007c2a45Smiod   relsec->contents = bfd_alloc (abfd, datasec->reloc_count * 12);
1384c074d1c9Sdrahn   if (relsec->contents == NULL)
13852159047fSniklas     goto error_return;
13862159047fSniklas 
1387c074d1c9Sdrahn   p = relsec->contents;
13882159047fSniklas 
1389c074d1c9Sdrahn   irelend = internal_relocs + datasec->reloc_count;
13902159047fSniklas 
1391c074d1c9Sdrahn   for (irel = internal_relocs; irel < irelend; irel++, p += 12)
13922159047fSniklas     {
1393c074d1c9Sdrahn       asection *targetsec;
13942159047fSniklas 
1395c074d1c9Sdrahn       /* We are going to write a four byte longword into the runtime
1396c074d1c9Sdrahn 	 reloc section.  The longword will be the address in the data
1397c074d1c9Sdrahn 	 section which must be relocated.  It is followed by the name
1398c074d1c9Sdrahn 	 of the target section NUL-padded or truncated to 8
1399c074d1c9Sdrahn 	 characters.  */
1400c074d1c9Sdrahn 
1401c074d1c9Sdrahn       /* We can only relocate absolute longword relocs at run time.  */
1402c074d1c9Sdrahn       if ((ELF32_R_TYPE (irel->r_info) != (int) R_MIPS_32) &&
1403c074d1c9Sdrahn 	  (ELF32_R_TYPE (irel->r_info) != (int) R_MIPS_64))
14042159047fSniklas 	{
1405c074d1c9Sdrahn 	  *errmsg = _("unsupported reloc type");
1406c074d1c9Sdrahn 	  bfd_set_error (bfd_error_bad_value);
1407c074d1c9Sdrahn 	  goto error_return;
1408c074d1c9Sdrahn 	}
1409c074d1c9Sdrahn       /* Get the target section referred to by the reloc.  */
1410c074d1c9Sdrahn       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1411c074d1c9Sdrahn 	{
1412c074d1c9Sdrahn           Elf_Internal_Sym *isym;
1413c074d1c9Sdrahn 
1414c074d1c9Sdrahn           /* A local symbol.  */
1415c074d1c9Sdrahn 	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
1416c074d1c9Sdrahn 	  targetsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1417c074d1c9Sdrahn 	}
14182159047fSniklas       else
14192159047fSniklas 	{
1420c074d1c9Sdrahn 	  unsigned long indx;
1421c074d1c9Sdrahn 	  struct elf_link_hash_entry *h;
14222159047fSniklas 
1423c074d1c9Sdrahn 	  /* An external symbol.  */
1424c074d1c9Sdrahn 	  indx = ELF32_R_SYM (irel->r_info);
1425c074d1c9Sdrahn 	  h = elf_sym_hashes (abfd)[indx];
1426c074d1c9Sdrahn 	  targetsec = NULL;
1427c074d1c9Sdrahn 	  /*
1428c074d1c9Sdrahn 	     For some reason, in certain programs, the symbol will
1429c074d1c9Sdrahn 	     not be in the hash table.  It seems to happen when you
1430c074d1c9Sdrahn 	     declare a static table of pointers to const external structures.
1431c074d1c9Sdrahn 	     In this case, the relocs are relative to data, not
1432c074d1c9Sdrahn 	     text, so just treating it like an undefined link
1433c074d1c9Sdrahn 	     should be sufficient.  */
1434c074d1c9Sdrahn 	  BFD_ASSERT(h != NULL);
1435c074d1c9Sdrahn 	  if (h->root.type == bfd_link_hash_defined
1436c074d1c9Sdrahn 	      || h->root.type == bfd_link_hash_defweak)
1437c074d1c9Sdrahn 	    targetsec = h->root.u.def.section;
14382159047fSniklas 	}
14392159047fSniklas 
1440c074d1c9Sdrahn 
1441c074d1c9Sdrahn       /*
1442c074d1c9Sdrahn          Set the low bit of the relocation offset if it's a MIPS64 reloc.
1443c074d1c9Sdrahn          Relocations will always be on (at least) 32-bit boundaries.  */
1444c074d1c9Sdrahn 
1445c074d1c9Sdrahn       bfd_put_32 (abfd, ((irel->r_offset + datasec->output_offset) +
1446c074d1c9Sdrahn 		  ((ELF32_R_TYPE (irel->r_info) == (int) R_MIPS_64) ? 1 : 0)),
1447c074d1c9Sdrahn 		  p);
1448c074d1c9Sdrahn       memset (p + 4, 0, 8);
1449c074d1c9Sdrahn       if (targetsec != NULL)
1450c074d1c9Sdrahn 	strncpy (p + 4, targetsec->output_section->name, 8);
14512159047fSniklas     }
14522159047fSniklas 
1453c074d1c9Sdrahn   if (internal_relocs != NULL
1454c074d1c9Sdrahn       && elf_section_data (datasec)->relocs != internal_relocs)
1455c074d1c9Sdrahn     free (internal_relocs);
1456c074d1c9Sdrahn   if (isymbuf != NULL
1457c074d1c9Sdrahn       && symtab_hdr->contents != (unsigned char *) isymbuf)
1458c074d1c9Sdrahn     free (isymbuf);
1459c074d1c9Sdrahn   return TRUE;
14602159047fSniklas 
14612159047fSniklas  error_return:
1462c074d1c9Sdrahn   if (internal_relocs != NULL
1463c074d1c9Sdrahn       && elf_section_data (datasec)->relocs != internal_relocs)
1464c074d1c9Sdrahn     free (internal_relocs);
1465c074d1c9Sdrahn   if (isymbuf != NULL
1466c074d1c9Sdrahn       && symtab_hdr->contents != (unsigned char *) isymbuf)
1467c074d1c9Sdrahn     free (isymbuf);
1468c074d1c9Sdrahn   return FALSE;
14692159047fSniklas }
14702159047fSniklas 
14712159047fSniklas /* ECOFF swapping routines.  These are used when dealing with the
14722159047fSniklas    .mdebug section, which is in the ECOFF debugging format.  */
1473b55d4692Sfgsch static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
14742159047fSniklas   /* Symbol table magic number.  */
14752159047fSniklas   magicSym,
14762159047fSniklas   /* Alignment of debugging information.  E.g., 4.  */
14772159047fSniklas   4,
14782159047fSniklas   /* Sizes of external symbolic information.  */
14792159047fSniklas   sizeof (struct hdr_ext),
14802159047fSniklas   sizeof (struct dnr_ext),
14812159047fSniklas   sizeof (struct pdr_ext),
14822159047fSniklas   sizeof (struct sym_ext),
14832159047fSniklas   sizeof (struct opt_ext),
14842159047fSniklas   sizeof (struct fdr_ext),
14852159047fSniklas   sizeof (struct rfd_ext),
14862159047fSniklas   sizeof (struct ext_ext),
14872159047fSniklas   /* Functions to swap in external symbolic data.  */
14882159047fSniklas   ecoff_swap_hdr_in,
14892159047fSniklas   ecoff_swap_dnr_in,
14902159047fSniklas   ecoff_swap_pdr_in,
14912159047fSniklas   ecoff_swap_sym_in,
14922159047fSniklas   ecoff_swap_opt_in,
14932159047fSniklas   ecoff_swap_fdr_in,
14942159047fSniklas   ecoff_swap_rfd_in,
14952159047fSniklas   ecoff_swap_ext_in,
14962159047fSniklas   _bfd_ecoff_swap_tir_in,
14972159047fSniklas   _bfd_ecoff_swap_rndx_in,
14982159047fSniklas   /* Functions to swap out external symbolic data.  */
14992159047fSniklas   ecoff_swap_hdr_out,
15002159047fSniklas   ecoff_swap_dnr_out,
15012159047fSniklas   ecoff_swap_pdr_out,
15022159047fSniklas   ecoff_swap_sym_out,
15032159047fSniklas   ecoff_swap_opt_out,
15042159047fSniklas   ecoff_swap_fdr_out,
15052159047fSniklas   ecoff_swap_rfd_out,
15062159047fSniklas   ecoff_swap_ext_out,
15072159047fSniklas   _bfd_ecoff_swap_tir_out,
15082159047fSniklas   _bfd_ecoff_swap_rndx_out,
15092159047fSniklas   /* Function to read in symbolic data.  */
1510c88b1d6cSniklas   _bfd_mips_elf_read_ecoff_info
15112159047fSniklas };
15122159047fSniklas 
15132159047fSniklas #define ELF_ARCH			bfd_arch_mips
15142159047fSniklas #define ELF_MACHINE_CODE		EM_MIPS
15150c6d0228Sniklas 
1516c074d1c9Sdrahn #define elf_backend_collect		TRUE
1517c074d1c9Sdrahn #define elf_backend_type_change_ok	TRUE
1518c074d1c9Sdrahn #define elf_backend_can_gc_sections	TRUE
1519b305b0f1Sespie #define elf_info_to_howto		mips_info_to_howto_rela
15202159047fSniklas #define elf_info_to_howto_rel		mips_info_to_howto_rel
15212159047fSniklas #define elf_backend_sym_is_global	mips_elf_sym_is_global
1522c074d1c9Sdrahn #define elf_backend_object_p		mips_elf32_object_p
1523c074d1c9Sdrahn #define elf_backend_symbol_processing	_bfd_mips_elf_symbol_processing
1524c074d1c9Sdrahn #define elf_backend_section_processing	_bfd_mips_elf_section_processing
1525b305b0f1Sespie #define elf_backend_section_from_shdr	_bfd_mips_elf_section_from_shdr
1526c88b1d6cSniklas #define elf_backend_fake_sections	_bfd_mips_elf_fake_sections
15272159047fSniklas #define elf_backend_section_from_bfd_section \
1528c88b1d6cSniklas 					_bfd_mips_elf_section_from_bfd_section
1529b305b0f1Sespie #define elf_backend_add_symbol_hook	_bfd_mips_elf_add_symbol_hook
1530c074d1c9Sdrahn #define elf_backend_link_output_symbol_hook \
1531c074d1c9Sdrahn 					_bfd_mips_elf_link_output_symbol_hook
1532b305b0f1Sespie #define elf_backend_create_dynamic_sections \
1533b305b0f1Sespie 					_bfd_mips_elf_create_dynamic_sections
1534b305b0f1Sespie #define elf_backend_check_relocs	_bfd_mips_elf_check_relocs
1535b305b0f1Sespie #define elf_backend_adjust_dynamic_symbol \
1536b305b0f1Sespie 					_bfd_mips_elf_adjust_dynamic_symbol
1537b305b0f1Sespie #define elf_backend_always_size_sections \
1538b305b0f1Sespie 					_bfd_mips_elf_always_size_sections
1539b305b0f1Sespie #define elf_backend_size_dynamic_sections \
1540b305b0f1Sespie 					_bfd_mips_elf_size_dynamic_sections
1541b305b0f1Sespie #define elf_backend_relocate_section	_bfd_mips_elf_relocate_section
1542b305b0f1Sespie #define elf_backend_finish_dynamic_symbol \
1543b305b0f1Sespie 					_bfd_mips_elf_finish_dynamic_symbol
1544b305b0f1Sespie #define elf_backend_finish_dynamic_sections \
1545b305b0f1Sespie 					_bfd_mips_elf_finish_dynamic_sections
1546c074d1c9Sdrahn #define elf_backend_final_write_processing \
1547c074d1c9Sdrahn 					_bfd_mips_elf_final_write_processing
1548c074d1c9Sdrahn #define elf_backend_additional_program_headers \
1549c074d1c9Sdrahn 					_bfd_mips_elf_additional_program_headers
1550c074d1c9Sdrahn #define elf_backend_modify_segment_map	_bfd_mips_elf_modify_segment_map
1551b305b0f1Sespie #define elf_backend_gc_mark_hook	_bfd_mips_elf_gc_mark_hook
1552b305b0f1Sespie #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
1553c074d1c9Sdrahn #define elf_backend_copy_indirect_symbol \
1554c074d1c9Sdrahn 					_bfd_mips_elf_copy_indirect_symbol
1555c074d1c9Sdrahn #define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
1556c074d1c9Sdrahn #define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
1557c074d1c9Sdrahn #define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
1558c074d1c9Sdrahn #define elf_backend_ecoff_debug_swap	&mips_elf32_ecoff_debug_swap
15592159047fSniklas 
1560b305b0f1Sespie #define elf_backend_got_header_size	(4 * MIPS_RESERVED_GOTNO)
1561c074d1c9Sdrahn #define elf_backend_may_use_rel_p	1
1562c074d1c9Sdrahn #define elf_backend_may_use_rela_p	0
1563c074d1c9Sdrahn #define elf_backend_default_use_rela_p	0
1564c074d1c9Sdrahn #define elf_backend_sign_extend_vma	TRUE
1565b305b0f1Sespie 
1566c074d1c9Sdrahn #define elf_backend_discard_info	_bfd_mips_elf_discard_info
1567c074d1c9Sdrahn #define elf_backend_ignore_discarded_relocs \
1568c074d1c9Sdrahn 					_bfd_mips_elf_ignore_discarded_relocs
1569c074d1c9Sdrahn #define elf_backend_mips_irix_compat	elf32_mips_irix_compat
1570c074d1c9Sdrahn #define elf_backend_mips_rtype_to_howto	mips_elf32_rtype_to_howto
1571b305b0f1Sespie #define bfd_elf32_bfd_is_local_label_name \
1572b305b0f1Sespie 					mips_elf_is_local_label_name
1573c88b1d6cSniklas #define bfd_elf32_find_nearest_line	_bfd_mips_elf_find_nearest_line
1574c074d1c9Sdrahn #define bfd_elf32_new_section_hook	_bfd_mips_elf_new_section_hook
1575c88b1d6cSniklas #define bfd_elf32_set_section_contents	_bfd_mips_elf_set_section_contents
1576c074d1c9Sdrahn #define bfd_elf32_bfd_get_relocated_section_contents \
1577c074d1c9Sdrahn 				_bfd_elf_mips_get_relocated_section_contents
15782159047fSniklas #define bfd_elf32_bfd_link_hash_table_create \
1579b305b0f1Sespie 					_bfd_mips_elf_link_hash_table_create
1580b305b0f1Sespie #define bfd_elf32_bfd_final_link	_bfd_mips_elf_final_link
1581c88b1d6cSniklas #define bfd_elf32_bfd_merge_private_bfd_data \
1582c88b1d6cSniklas 					_bfd_mips_elf_merge_private_bfd_data
1583c88b1d6cSniklas #define bfd_elf32_bfd_set_private_flags	_bfd_mips_elf_set_private_flags
1584b305b0f1Sespie #define bfd_elf32_bfd_print_private_bfd_data \
1585b305b0f1Sespie 					_bfd_mips_elf_print_private_bfd_data
1586c074d1c9Sdrahn 
1587c074d1c9Sdrahn /* Support for SGI-ish mips targets.  */
1588c074d1c9Sdrahn #define TARGET_LITTLE_SYM		bfd_elf32_littlemips_vec
1589c074d1c9Sdrahn #define TARGET_LITTLE_NAME		"elf32-littlemips"
1590c074d1c9Sdrahn #define TARGET_BIG_SYM			bfd_elf32_bigmips_vec
1591c074d1c9Sdrahn #define TARGET_BIG_NAME			"elf32-bigmips"
1592c074d1c9Sdrahn 
1593*007c2a45Smiod /* The SVR4 MIPS ABI says that this should be 0x10000, but Irix 5 uses
1594*007c2a45Smiod    a value of 0x1000, and we are compatible.  */
1595*007c2a45Smiod #define ELF_MAXPAGESIZE			0x1000
1596*007c2a45Smiod 
15972159047fSniklas #include "elf32-target.h"
1598b55d4692Sfgsch 
1599c074d1c9Sdrahn /* Support for traditional mips targets.  */
1600b55d4692Sfgsch #undef TARGET_LITTLE_SYM
1601b55d4692Sfgsch #undef TARGET_LITTLE_NAME
1602b55d4692Sfgsch #undef TARGET_BIG_SYM
1603b55d4692Sfgsch #undef TARGET_BIG_NAME
1604b55d4692Sfgsch 
1605*007c2a45Smiod #undef ELF_MAXPAGESIZE
1606*007c2a45Smiod 
1607b55d4692Sfgsch #define TARGET_LITTLE_SYM               bfd_elf32_tradlittlemips_vec
1608b55d4692Sfgsch #define TARGET_LITTLE_NAME              "elf32-tradlittlemips"
1609b55d4692Sfgsch #define TARGET_BIG_SYM                  bfd_elf32_tradbigmips_vec
1610b55d4692Sfgsch #define TARGET_BIG_NAME                 "elf32-tradbigmips"
1611b55d4692Sfgsch 
1612*007c2a45Smiod /* The SVR4 MIPS ABI says that this should be 0x10000, and Linux uses
1613*007c2a45Smiod    page sizes of up to that limit, so we need to respect it.  */
1614*007c2a45Smiod #define ELF_MAXPAGESIZE			0x10000
1615*007c2a45Smiod #define elf32_bed			elf32_tradbed
1616*007c2a45Smiod 
1617c074d1c9Sdrahn /* Include the target file again for this target.  */
1618b55d4692Sfgsch #include "elf32-target.h"
1619