xref: /openbsd-src/gnu/usr.bin/binutils/bfd/coff-mips.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* BFD back-end for MIPS Extended-Coff files.
2b55d4692Sfgsch    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3*007c2a45Smiod    2000, 2001, 2002, 2003
4b305b0f1Sespie    Free Software Foundation, Inc.
52159047fSniklas    Original version by Per Bothner.
62159047fSniklas    Full support added by Ian Lance Taylor, ian@cygnus.com.
72159047fSniklas 
82159047fSniklas This file is part of BFD, the Binary File Descriptor library.
92159047fSniklas 
102159047fSniklas This program is free software; you can redistribute it and/or modify
112159047fSniklas it under the terms of the GNU General Public License as published by
122159047fSniklas the Free Software Foundation; either version 2 of the License, or
132159047fSniklas (at your option) any later version.
142159047fSniklas 
152159047fSniklas This program is distributed in the hope that it will be useful,
162159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
172159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
182159047fSniklas GNU General Public License for more details.
192159047fSniklas 
202159047fSniklas You should have received a copy of the GNU General Public License
212159047fSniklas along with this program; if not, write to the Free Software
222159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
232159047fSniklas 
242159047fSniklas #include "bfd.h"
252159047fSniklas #include "sysdep.h"
262159047fSniklas #include "bfdlink.h"
272159047fSniklas #include "libbfd.h"
282159047fSniklas #include "coff/internal.h"
292159047fSniklas #include "coff/sym.h"
302159047fSniklas #include "coff/symconst.h"
312159047fSniklas #include "coff/ecoff.h"
322159047fSniklas #include "coff/mips.h"
332159047fSniklas #include "libcoff.h"
342159047fSniklas #include "libecoff.h"
352159047fSniklas 
362159047fSniklas /* Prototypes for static functions.  */
372159047fSniklas 
38c074d1c9Sdrahn static bfd_boolean mips_ecoff_bad_format_hook
39c074d1c9Sdrahn   PARAMS ((bfd *abfd, PTR filehdr));
40c074d1c9Sdrahn static void mips_ecoff_swap_reloc_in
41c074d1c9Sdrahn   PARAMS ((bfd *, PTR, struct internal_reloc *));
42c074d1c9Sdrahn static void mips_ecoff_swap_reloc_out
43c074d1c9Sdrahn   PARAMS ((bfd *, const struct internal_reloc *, PTR));
44c074d1c9Sdrahn static void mips_adjust_reloc_in
45c074d1c9Sdrahn   PARAMS ((bfd *, const struct internal_reloc *, arelent *));
46c074d1c9Sdrahn static void mips_adjust_reloc_out
47c074d1c9Sdrahn   PARAMS ((bfd *, const arelent *, struct internal_reloc *));
48c074d1c9Sdrahn static bfd_reloc_status_type mips_generic_reloc
49c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
50c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
51c074d1c9Sdrahn static bfd_reloc_status_type mips_refhi_reloc
52c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
53c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
54c074d1c9Sdrahn static bfd_reloc_status_type mips_reflo_reloc
55c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
56c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
57c074d1c9Sdrahn static bfd_reloc_status_type mips_gprel_reloc
58c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
59c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
60c074d1c9Sdrahn static bfd_reloc_status_type mips_relhi_reloc
61c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
62c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
63c074d1c9Sdrahn static bfd_reloc_status_type mips_rello_reloc
64c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
65c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
66c074d1c9Sdrahn static bfd_reloc_status_type mips_switch_reloc
67c074d1c9Sdrahn   PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
68c074d1c9Sdrahn 	   asection *section, bfd *output_bfd, char **error));
69c074d1c9Sdrahn static void mips_relocate_hi
70c074d1c9Sdrahn   PARAMS ((struct internal_reloc *refhi, struct internal_reloc *reflo,
71c074d1c9Sdrahn 	   bfd *input_bfd, asection *input_section, bfd_byte *contents,
72c074d1c9Sdrahn 	   size_t adjust, bfd_vma relocation, bfd_boolean pcrel));
73c074d1c9Sdrahn static bfd_boolean mips_relocate_section
74c074d1c9Sdrahn   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PTR));
75c074d1c9Sdrahn static bfd_boolean mips_read_relocs
76c074d1c9Sdrahn   PARAMS ((bfd *, asection *));
77c074d1c9Sdrahn static bfd_boolean mips_relax_section
78c074d1c9Sdrahn   PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
79c074d1c9Sdrahn static bfd_boolean mips_relax_pcrel16
80c074d1c9Sdrahn   PARAMS ((struct bfd_link_info *, bfd *, asection *,
81c074d1c9Sdrahn 	   struct ecoff_link_hash_entry *, bfd_byte *, bfd_vma));
82e93f7393Sniklas static reloc_howto_type *mips_bfd_reloc_type_lookup
83e93f7393Sniklas   PARAMS ((bfd *, bfd_reloc_code_real_type));
842159047fSniklas 
852159047fSniklas /* ECOFF has COFF sections, but the debugging information is stored in
862159047fSniklas    a completely different format.  ECOFF targets use some of the
872159047fSniklas    swapping routines from coffswap.h, and some of the generic COFF
882159047fSniklas    routines in coffgen.c, but, unlike the real COFF targets, do not
892159047fSniklas    use coffcode.h itself.
902159047fSniklas 
912159047fSniklas    Get the generic COFF swapping routines, except for the reloc,
922159047fSniklas    symbol, and lineno ones.  Give them ECOFF names.  */
932159047fSniklas #define MIPSECOFF
942159047fSniklas #define NO_COFF_RELOCS
952159047fSniklas #define NO_COFF_SYMBOLS
962159047fSniklas #define NO_COFF_LINENOS
972159047fSniklas #define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in
982159047fSniklas #define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out
992159047fSniklas #define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in
1002159047fSniklas #define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out
1012159047fSniklas #define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in
1022159047fSniklas #define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out
1032159047fSniklas #include "coffswap.h"
1042159047fSniklas 
1052159047fSniklas /* Get the ECOFF swapping routines.  */
1062159047fSniklas #define ECOFF_32
1072159047fSniklas #include "ecoffswap.h"
1082159047fSniklas 
1092159047fSniklas /* How to process the various relocs types.  */
1102159047fSniklas 
1112159047fSniklas static reloc_howto_type mips_howto_table[] =
1122159047fSniklas {
1132159047fSniklas   /* Reloc type 0 is ignored.  The reloc reading code ensures that
1142159047fSniklas      this is a reference to the .abs section, which will cause
1152159047fSniklas      bfd_perform_relocation to do nothing.  */
1162159047fSniklas   HOWTO (MIPS_R_IGNORE,	/* type */
1172159047fSniklas 	 0,			/* rightshift */
1182159047fSniklas 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1192159047fSniklas 	 8,			/* bitsize */
120c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1212159047fSniklas 	 0,			/* bitpos */
1222159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1232159047fSniklas 	 0,			/* special_function */
1242159047fSniklas 	 "IGNORE",		/* name */
125c074d1c9Sdrahn 	 FALSE,			/* partial_inplace */
1262159047fSniklas 	 0,			/* src_mask */
1272159047fSniklas 	 0,			/* dst_mask */
128c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1292159047fSniklas 
1302159047fSniklas   /* A 16 bit reference to a symbol, normally from a data section.  */
1312159047fSniklas   HOWTO (MIPS_R_REFHALF,	/* type */
1322159047fSniklas 	 0,			/* rightshift */
1332159047fSniklas 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
1342159047fSniklas 	 16,			/* bitsize */
135c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1362159047fSniklas 	 0,			/* bitpos */
1372159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
1382159047fSniklas 	 mips_generic_reloc,	/* special_function */
1392159047fSniklas 	 "REFHALF",		/* name */
140c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1412159047fSniklas 	 0xffff,		/* src_mask */
1422159047fSniklas 	 0xffff,		/* dst_mask */
143c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1442159047fSniklas 
1452159047fSniklas   /* A 32 bit reference to a symbol, normally from a data section.  */
1462159047fSniklas   HOWTO (MIPS_R_REFWORD,	/* type */
1472159047fSniklas 	 0,			/* rightshift */
1482159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1492159047fSniklas 	 32,			/* bitsize */
150c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1512159047fSniklas 	 0,			/* bitpos */
1522159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
1532159047fSniklas 	 mips_generic_reloc,	/* special_function */
1542159047fSniklas 	 "REFWORD",		/* name */
155c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1562159047fSniklas 	 0xffffffff,		/* src_mask */
1572159047fSniklas 	 0xffffffff,		/* dst_mask */
158c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1592159047fSniklas 
1602159047fSniklas   /* A 26 bit absolute jump address.  */
1612159047fSniklas   HOWTO (MIPS_R_JMPADDR,	/* type */
1622159047fSniklas 	 2,			/* rightshift */
1632159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1642159047fSniklas 	 26,			/* bitsize */
165c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1662159047fSniklas 	 0,			/* bitpos */
1672159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
1682159047fSniklas 	 			/* This needs complex overflow
1692159047fSniklas 				   detection, because the upper four
1702159047fSniklas 				   bits must match the PC.  */
1712159047fSniklas 	 mips_generic_reloc,	/* special_function */
1722159047fSniklas 	 "JMPADDR",		/* name */
173c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1742159047fSniklas 	 0x3ffffff,		/* src_mask */
1752159047fSniklas 	 0x3ffffff,		/* dst_mask */
176c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1772159047fSniklas 
1782159047fSniklas   /* The high 16 bits of a symbol value.  Handled by the function
1792159047fSniklas      mips_refhi_reloc.  */
1802159047fSniklas   HOWTO (MIPS_R_REFHI,		/* type */
1812159047fSniklas 	 16,			/* rightshift */
1822159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1832159047fSniklas 	 16,			/* bitsize */
184c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
1852159047fSniklas 	 0,			/* bitpos */
1862159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
1872159047fSniklas 	 mips_refhi_reloc,	/* special_function */
1882159047fSniklas 	 "REFHI",		/* name */
189c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
1902159047fSniklas 	 0xffff,		/* src_mask */
1912159047fSniklas 	 0xffff,		/* dst_mask */
192c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
1932159047fSniklas 
1942159047fSniklas   /* The low 16 bits of a symbol value.  */
1952159047fSniklas   HOWTO (MIPS_R_REFLO,		/* type */
1962159047fSniklas 	 0,			/* rightshift */
1972159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1982159047fSniklas 	 16,			/* bitsize */
199c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2002159047fSniklas 	 0,			/* bitpos */
2012159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
2022159047fSniklas 	 mips_reflo_reloc,	/* special_function */
2032159047fSniklas 	 "REFLO",		/* name */
204c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2052159047fSniklas 	 0xffff,		/* src_mask */
2062159047fSniklas 	 0xffff,		/* dst_mask */
207c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2082159047fSniklas 
2092159047fSniklas   /* A reference to an offset from the gp register.  Handled by the
2102159047fSniklas      function mips_gprel_reloc.  */
2112159047fSniklas   HOWTO (MIPS_R_GPREL,		/* type */
2122159047fSniklas 	 0,			/* rightshift */
2132159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2142159047fSniklas 	 16,			/* bitsize */
215c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2162159047fSniklas 	 0,			/* bitpos */
2172159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
2182159047fSniklas 	 mips_gprel_reloc,	/* special_function */
2192159047fSniklas 	 "GPREL",		/* name */
220c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2212159047fSniklas 	 0xffff,		/* src_mask */
2222159047fSniklas 	 0xffff,		/* dst_mask */
223c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2242159047fSniklas 
2252159047fSniklas   /* A reference to a literal using an offset from the gp register.
2262159047fSniklas      Handled by the function mips_gprel_reloc.  */
2272159047fSniklas   HOWTO (MIPS_R_LITERAL,	/* type */
2282159047fSniklas 	 0,			/* rightshift */
2292159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2302159047fSniklas 	 16,			/* bitsize */
231c074d1c9Sdrahn 	 FALSE,			/* pc_relative */
2322159047fSniklas 	 0,			/* bitpos */
2332159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
2342159047fSniklas 	 mips_gprel_reloc,	/* special_function */
2352159047fSniklas 	 "LITERAL",		/* name */
236c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2372159047fSniklas 	 0xffff,		/* src_mask */
2382159047fSniklas 	 0xffff,		/* dst_mask */
239c074d1c9Sdrahn 	 FALSE),		/* pcrel_offset */
2402159047fSniklas 
241b305b0f1Sespie   EMPTY_HOWTO (8),
242b305b0f1Sespie   EMPTY_HOWTO (9),
243b305b0f1Sespie   EMPTY_HOWTO (10),
244b305b0f1Sespie   EMPTY_HOWTO (11),
2452159047fSniklas 
2462159047fSniklas   /* This reloc is a Cygnus extension used when generating position
2472159047fSniklas      independent code for embedded systems.  It represents a 16 bit PC
2482159047fSniklas      relative reloc rightshifted twice as used in the MIPS branch
2492159047fSniklas      instructions.  */
2502159047fSniklas   HOWTO (MIPS_R_PCREL16,	/* type */
2512159047fSniklas 	 2,			/* rightshift */
2522159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2532159047fSniklas 	 16,			/* bitsize */
254c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
2552159047fSniklas 	 0,			/* bitpos */
2562159047fSniklas 	 complain_overflow_signed, /* complain_on_overflow */
2572159047fSniklas 	 mips_generic_reloc,	/* special_function */
2582159047fSniklas 	 "PCREL16",		/* name */
259c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2602159047fSniklas 	 0xffff,		/* src_mask */
2612159047fSniklas 	 0xffff,		/* dst_mask */
262c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
2632159047fSniklas 
2642159047fSniklas   /* This reloc is a Cygnus extension used when generating position
2652159047fSniklas      independent code for embedded systems.  It represents the high 16
2662159047fSniklas      bits of a PC relative reloc.  The next reloc must be
2672159047fSniklas      MIPS_R_RELLO, and the addend is formed from the addends of the
2682159047fSniklas      two instructions, just as in MIPS_R_REFHI and MIPS_R_REFLO.  The
2692159047fSniklas      final value is actually PC relative to the location of the
2702159047fSniklas      MIPS_R_RELLO reloc, not the MIPS_R_RELHI reloc.  */
2712159047fSniklas   HOWTO (MIPS_R_RELHI,		/* type */
2722159047fSniklas 	 16,			/* rightshift */
2732159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2742159047fSniklas 	 16,			/* bitsize */
275c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
2762159047fSniklas 	 0,			/* bitpos */
2772159047fSniklas 	 complain_overflow_bitfield, /* complain_on_overflow */
2782159047fSniklas 	 mips_relhi_reloc,	/* special_function */
2792159047fSniklas 	 "RELHI",		/* name */
280c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2812159047fSniklas 	 0xffff,		/* src_mask */
2822159047fSniklas 	 0xffff,		/* dst_mask */
283c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
2842159047fSniklas 
2852159047fSniklas   /* This reloc is a Cygnus extension used when generating position
2862159047fSniklas      independent code for embedded systems.  It represents the low 16
2872159047fSniklas      bits of a PC relative reloc.  */
2882159047fSniklas   HOWTO (MIPS_R_RELLO,		/* type */
2892159047fSniklas 	 0,			/* rightshift */
2902159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2912159047fSniklas 	 16,			/* bitsize */
292c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
2932159047fSniklas 	 0,			/* bitpos */
2942159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
2952159047fSniklas 	 mips_rello_reloc,	/* special_function */
2962159047fSniklas 	 "RELLO",		/* name */
297c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
2982159047fSniklas 	 0xffff,		/* src_mask */
2992159047fSniklas 	 0xffff,		/* dst_mask */
300c074d1c9Sdrahn 	 TRUE),			/* pcrel_offset */
3012159047fSniklas 
302b305b0f1Sespie   EMPTY_HOWTO (15),
303b305b0f1Sespie   EMPTY_HOWTO (16),
304b305b0f1Sespie   EMPTY_HOWTO (17),
305b305b0f1Sespie   EMPTY_HOWTO (18),
306b305b0f1Sespie   EMPTY_HOWTO (19),
307b305b0f1Sespie   EMPTY_HOWTO (20),
308b305b0f1Sespie   EMPTY_HOWTO (21),
3092159047fSniklas 
3102159047fSniklas   /* This reloc is a Cygnus extension used when generating position
3112159047fSniklas      independent code for embedded systems.  It represents an entry in
3122159047fSniklas      a switch table, which is the difference between two symbols in
3132159047fSniklas      the .text section.  The symndx is actually the offset from the
3142159047fSniklas      reloc address to the subtrahend.  See include/coff/mips.h for
3152159047fSniklas      more details.  */
3162159047fSniklas   HOWTO (MIPS_R_SWITCH,		/* type */
3172159047fSniklas 	 0,			/* rightshift */
3182159047fSniklas 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
3192159047fSniklas 	 32,			/* bitsize */
320c074d1c9Sdrahn 	 TRUE,			/* pc_relative */
3212159047fSniklas 	 0,			/* bitpos */
3222159047fSniklas 	 complain_overflow_dont, /* complain_on_overflow */
3232159047fSniklas 	 mips_switch_reloc,	/* special_function */
3242159047fSniklas 	 "SWITCH",		/* name */
325c074d1c9Sdrahn 	 TRUE,			/* partial_inplace */
3262159047fSniklas 	 0xffffffff,		/* src_mask */
3272159047fSniklas 	 0xffffffff,		/* dst_mask */
328c074d1c9Sdrahn 	 TRUE)			/* pcrel_offset */
3292159047fSniklas };
3302159047fSniklas 
3312159047fSniklas #define MIPS_HOWTO_COUNT \
3322159047fSniklas   (sizeof mips_howto_table / sizeof mips_howto_table[0])
3332159047fSniklas 
334c074d1c9Sdrahn /* When the linker is doing relaxing, it may change an external PCREL16
3352159047fSniklas    reloc.  This typically represents an instruction like
3362159047fSniklas        bal foo
3372159047fSniklas    We change it to
3382159047fSniklas        .set  noreorder
3392159047fSniklas        bal   $L1
3402159047fSniklas        lui   $at,%hi(foo - $L1)
3412159047fSniklas      $L1:
3422159047fSniklas        addiu $at,%lo(foo - $L1)
3432159047fSniklas        addu  $at,$at,$31
3442159047fSniklas        jalr  $at
3452159047fSniklas    PCREL16_EXPANSION_ADJUSTMENT is the number of bytes this changes the
3462159047fSniklas    instruction by.  */
3472159047fSniklas 
3482159047fSniklas #define PCREL16_EXPANSION_ADJUSTMENT (4 * 4)
3492159047fSniklas 
3502159047fSniklas /* See whether the magic number matches.  */
3512159047fSniklas 
352c074d1c9Sdrahn static bfd_boolean
mips_ecoff_bad_format_hook(abfd,filehdr)3532159047fSniklas mips_ecoff_bad_format_hook (abfd, filehdr)
3542159047fSniklas      bfd *abfd;
3552159047fSniklas      PTR filehdr;
3562159047fSniklas {
3572159047fSniklas   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
3582159047fSniklas 
3592159047fSniklas   switch (internal_f->f_magic)
3602159047fSniklas     {
3612159047fSniklas     case MIPS_MAGIC_1:
3622159047fSniklas       /* I don't know what endianness this implies.  */
363c074d1c9Sdrahn       return TRUE;
3642159047fSniklas 
3652159047fSniklas     case MIPS_MAGIC_BIG:
3662159047fSniklas     case MIPS_MAGIC_BIG2:
3672159047fSniklas     case MIPS_MAGIC_BIG3:
368c88b1d6cSniklas       return bfd_big_endian (abfd);
3692159047fSniklas 
3702159047fSniklas     case MIPS_MAGIC_LITTLE:
3712159047fSniklas     case MIPS_MAGIC_LITTLE2:
3722159047fSniklas     case MIPS_MAGIC_LITTLE3:
373c88b1d6cSniklas       return bfd_little_endian (abfd);
3742159047fSniklas 
3752159047fSniklas     default:
376c074d1c9Sdrahn       return FALSE;
3772159047fSniklas     }
3782159047fSniklas }
3792159047fSniklas 
3802159047fSniklas /* Reloc handling.  MIPS ECOFF relocs are packed into 8 bytes in
3812159047fSniklas    external form.  They use a bit which indicates whether the symbol
3822159047fSniklas    is external.  */
3832159047fSniklas 
3842159047fSniklas /* Swap a reloc in.  */
3852159047fSniklas 
3862159047fSniklas static void
mips_ecoff_swap_reloc_in(abfd,ext_ptr,intern)3872159047fSniklas mips_ecoff_swap_reloc_in (abfd, ext_ptr, intern)
3882159047fSniklas      bfd *abfd;
3892159047fSniklas      PTR ext_ptr;
3902159047fSniklas      struct internal_reloc *intern;
3912159047fSniklas {
3922159047fSniklas   const RELOC *ext = (RELOC *) ext_ptr;
3932159047fSniklas 
394c074d1c9Sdrahn   intern->r_vaddr = H_GET_32 (abfd, ext->r_vaddr);
395c88b1d6cSniklas   if (bfd_header_big_endian (abfd))
3962159047fSniklas     {
3972159047fSniklas       intern->r_symndx = (((int) ext->r_bits[0]
3982159047fSniklas 			   << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
3992159047fSniklas 			  | ((int) ext->r_bits[1]
4002159047fSniklas 			     << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
4012159047fSniklas 			  | ((int) ext->r_bits[2]
4022159047fSniklas 			     << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
4032159047fSniklas       intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
4042159047fSniklas 			>> RELOC_BITS3_TYPE_SH_BIG);
4052159047fSniklas       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
4062159047fSniklas     }
4072159047fSniklas   else
4082159047fSniklas     {
4092159047fSniklas       intern->r_symndx = (((int) ext->r_bits[0]
4102159047fSniklas 			   << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
4112159047fSniklas 			  | ((int) ext->r_bits[1]
4122159047fSniklas 			     << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
4132159047fSniklas 			  | ((int) ext->r_bits[2]
4142159047fSniklas 			     << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
4152159047fSniklas       intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
4162159047fSniklas 			 >> RELOC_BITS3_TYPE_SH_LITTLE)
4172159047fSniklas 			| ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE)
4182159047fSniklas 			   << RELOC_BITS3_TYPEHI_SH_LITTLE));
4192159047fSniklas       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
4202159047fSniklas     }
4212159047fSniklas 
4222159047fSniklas   /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or
4232159047fSniklas      MIPS_R_RELLO reloc, r_symndx is actually the offset from the
4242159047fSniklas      reloc address to the base of the difference (see
4252159047fSniklas      include/coff/mips.h for more details).  We copy symndx into the
4262159047fSniklas      r_offset field so as not to confuse ecoff_slurp_reloc_table in
4272159047fSniklas      ecoff.c.  In adjust_reloc_in we then copy r_offset into the reloc
4282159047fSniklas      addend.  */
4292159047fSniklas   if (intern->r_type == MIPS_R_SWITCH
4302159047fSniklas       || (! intern->r_extern
4312159047fSniklas 	  && (intern->r_type == MIPS_R_RELLO
4322159047fSniklas 	      || intern->r_type == MIPS_R_RELHI)))
4332159047fSniklas     {
4342159047fSniklas       BFD_ASSERT (! intern->r_extern);
4352159047fSniklas       intern->r_offset = intern->r_symndx;
4362159047fSniklas       if (intern->r_offset & 0x800000)
4372159047fSniklas 	intern->r_offset -= 0x1000000;
4382159047fSniklas       intern->r_symndx = RELOC_SECTION_TEXT;
4392159047fSniklas     }
4402159047fSniklas }
4412159047fSniklas 
4422159047fSniklas /* Swap a reloc out.  */
4432159047fSniklas 
4442159047fSniklas static void
mips_ecoff_swap_reloc_out(abfd,intern,dst)4452159047fSniklas mips_ecoff_swap_reloc_out (abfd, intern, dst)
4462159047fSniklas      bfd *abfd;
4472159047fSniklas      const struct internal_reloc *intern;
4482159047fSniklas      PTR dst;
4492159047fSniklas {
4502159047fSniklas   RELOC *ext = (RELOC *) dst;
4512159047fSniklas   long r_symndx;
4522159047fSniklas 
4532159047fSniklas   BFD_ASSERT (intern->r_extern
4542159047fSniklas 	      || (intern->r_symndx >= 0 && intern->r_symndx <= 12));
4552159047fSniklas 
4562159047fSniklas   /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELLO or
4572159047fSniklas      MIPS_R_RELHI reloc, we actually want to write the contents of
4582159047fSniklas      r_offset out as the symbol index.  This undoes the change made by
4592159047fSniklas      mips_ecoff_swap_reloc_in.  */
4602159047fSniklas   if (intern->r_type != MIPS_R_SWITCH
4612159047fSniklas       && (intern->r_extern
4622159047fSniklas 	  || (intern->r_type != MIPS_R_RELHI
4632159047fSniklas 	      && intern->r_type != MIPS_R_RELLO)))
4642159047fSniklas     r_symndx = intern->r_symndx;
4652159047fSniklas   else
4662159047fSniklas     {
4672159047fSniklas       BFD_ASSERT (intern->r_symndx == RELOC_SECTION_TEXT);
4682159047fSniklas       r_symndx = intern->r_offset & 0xffffff;
4692159047fSniklas     }
4702159047fSniklas 
471c074d1c9Sdrahn   H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr);
472c88b1d6cSniklas   if (bfd_header_big_endian (abfd))
4732159047fSniklas     {
4742159047fSniklas       ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
4752159047fSniklas       ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
4762159047fSniklas       ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
4772159047fSniklas       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
4782159047fSniklas 			 & RELOC_BITS3_TYPE_BIG)
4792159047fSniklas 			| (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
4802159047fSniklas     }
4812159047fSniklas   else
4822159047fSniklas     {
4832159047fSniklas       ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
4842159047fSniklas       ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
4852159047fSniklas       ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
4862159047fSniklas       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
4872159047fSniklas 			 & RELOC_BITS3_TYPE_LITTLE)
4882159047fSniklas 			| ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE
4892159047fSniklas 			    & RELOC_BITS3_TYPEHI_LITTLE))
4902159047fSniklas 			| (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
4912159047fSniklas     }
4922159047fSniklas }
4932159047fSniklas 
4942159047fSniklas /* Finish canonicalizing a reloc.  Part of this is generic to all
4952159047fSniklas    ECOFF targets, and that part is in ecoff.c.  The rest is done in
4962159047fSniklas    this backend routine.  It must fill in the howto field.  */
4972159047fSniklas 
4982159047fSniklas static void
mips_adjust_reloc_in(abfd,intern,rptr)4992159047fSniklas mips_adjust_reloc_in (abfd, intern, rptr)
5002159047fSniklas      bfd *abfd;
5012159047fSniklas      const struct internal_reloc *intern;
5022159047fSniklas      arelent *rptr;
5032159047fSniklas {
5042159047fSniklas   if (intern->r_type > MIPS_R_SWITCH)
5052159047fSniklas     abort ();
5062159047fSniklas 
5072159047fSniklas   if (! intern->r_extern
5082159047fSniklas       && (intern->r_type == MIPS_R_GPREL
5092159047fSniklas 	  || intern->r_type == MIPS_R_LITERAL))
5102159047fSniklas     rptr->addend += ecoff_data (abfd)->gp;
5112159047fSniklas 
5122159047fSniklas   /* If the type is MIPS_R_IGNORE, make sure this is a reference to
5132159047fSniklas      the absolute section so that the reloc is ignored.  */
5142159047fSniklas   if (intern->r_type == MIPS_R_IGNORE)
5152159047fSniklas     rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
5162159047fSniklas 
5172159047fSniklas   /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or
5182159047fSniklas      MIPS_R_RELLO reloc, we want the addend field of the BFD relocto
5192159047fSniklas      hold the value which was originally in the symndx field of the
5202159047fSniklas      internal MIPS ECOFF reloc.  This value was copied into
5212159047fSniklas      intern->r_offset by mips_swap_reloc_in, and here we copy it into
5222159047fSniklas      the addend field.  */
5232159047fSniklas   if (intern->r_type == MIPS_R_SWITCH
5242159047fSniklas       || (! intern->r_extern
5252159047fSniklas 	  && (intern->r_type == MIPS_R_RELHI
5262159047fSniklas 	      || intern->r_type == MIPS_R_RELLO)))
5272159047fSniklas     rptr->addend = intern->r_offset;
5282159047fSniklas 
5292159047fSniklas   rptr->howto = &mips_howto_table[intern->r_type];
5302159047fSniklas }
5312159047fSniklas 
5322159047fSniklas /* Make any adjustments needed to a reloc before writing it out.  None
5332159047fSniklas    are needed for MIPS.  */
5342159047fSniklas 
5352159047fSniklas static void
mips_adjust_reloc_out(abfd,rel,intern)5362159047fSniklas mips_adjust_reloc_out (abfd, rel, intern)
537b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
5382159047fSniklas      const arelent *rel;
5392159047fSniklas      struct internal_reloc *intern;
5402159047fSniklas {
5412159047fSniklas   /* For a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or
5422159047fSniklas      MIPS_R_RELLO reloc, we must copy rel->addend into
5432159047fSniklas      intern->r_offset.  This will then be written out as the symbol
5442159047fSniklas      index by mips_ecoff_swap_reloc_out.  This operation parallels the
5452159047fSniklas      action of mips_adjust_reloc_in.  */
5462159047fSniklas   if (intern->r_type == MIPS_R_SWITCH
5472159047fSniklas       || (! intern->r_extern
5482159047fSniklas 	  && (intern->r_type == MIPS_R_RELHI
5492159047fSniklas 	      || intern->r_type == MIPS_R_RELLO)))
5502159047fSniklas     intern->r_offset = rel->addend;
5512159047fSniklas }
5522159047fSniklas 
5532159047fSniklas /* ECOFF relocs are either against external symbols, or against
554*007c2a45Smiod    sections.  If we are producing relocatable output, and the reloc
5552159047fSniklas    is against an external symbol, and nothing has given us any
5562159047fSniklas    additional addend, the resulting reloc will also be against the
5572159047fSniklas    same symbol.  In such a case, we don't want to change anything
5582159047fSniklas    about the way the reloc is handled, since it will all be done at
5592159047fSniklas    final link time.  Rather than put special case code into
5602159047fSniklas    bfd_perform_relocation, all the reloc types use this howto
5612159047fSniklas    function.  It just short circuits the reloc if producing
562*007c2a45Smiod    relocatable output against an external symbol.  */
5632159047fSniklas 
5642159047fSniklas static bfd_reloc_status_type
mips_generic_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)5652159047fSniklas mips_generic_reloc (abfd,
5662159047fSniklas 		    reloc_entry,
5672159047fSniklas 		    symbol,
5682159047fSniklas 		    data,
5692159047fSniklas 		    input_section,
5702159047fSniklas 		    output_bfd,
5712159047fSniklas 		    error_message)
572b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
5732159047fSniklas      arelent *reloc_entry;
5742159047fSniklas      asymbol *symbol;
575b305b0f1Sespie      PTR data ATTRIBUTE_UNUSED;
5762159047fSniklas      asection *input_section;
5772159047fSniklas      bfd *output_bfd;
578b305b0f1Sespie      char **error_message ATTRIBUTE_UNUSED;
5792159047fSniklas {
5802159047fSniklas   if (output_bfd != (bfd *) NULL
5812159047fSniklas       && (symbol->flags & BSF_SECTION_SYM) == 0
5822159047fSniklas       && reloc_entry->addend == 0)
5832159047fSniklas     {
5842159047fSniklas       reloc_entry->address += input_section->output_offset;
5852159047fSniklas       return bfd_reloc_ok;
5862159047fSniklas     }
5872159047fSniklas 
5882159047fSniklas   return bfd_reloc_continue;
5892159047fSniklas }
5902159047fSniklas 
5912159047fSniklas /* Do a REFHI relocation.  This has to be done in combination with a
5922159047fSniklas    REFLO reloc, because there is a carry from the REFLO to the REFHI.
5932159047fSniklas    Here we just save the information we need; we do the actual
5942159047fSniklas    relocation when we see the REFLO.  MIPS ECOFF requires that the
5950c6d0228Sniklas    REFLO immediately follow the REFHI.  As a GNU extension, we permit
5960c6d0228Sniklas    an arbitrary number of HI relocs to be associated with a single LO
5970c6d0228Sniklas    reloc.  This extension permits gcc to output the HI and LO relocs
5980c6d0228Sniklas    itself.  */
5992159047fSniklas 
6000c6d0228Sniklas struct mips_hi
6010c6d0228Sniklas {
6020c6d0228Sniklas   struct mips_hi *next;
6030c6d0228Sniklas   bfd_byte *addr;
6040c6d0228Sniklas   bfd_vma addend;
6050c6d0228Sniklas };
6060c6d0228Sniklas 
6070c6d0228Sniklas /* FIXME: This should not be a static variable.  */
6080c6d0228Sniklas 
6090c6d0228Sniklas static struct mips_hi *mips_refhi_list;
6102159047fSniklas 
6112159047fSniklas static bfd_reloc_status_type
mips_refhi_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)6122159047fSniklas mips_refhi_reloc (abfd,
6132159047fSniklas 		  reloc_entry,
6142159047fSniklas 		  symbol,
6152159047fSniklas 		  data,
6162159047fSniklas 		  input_section,
6172159047fSniklas 		  output_bfd,
6182159047fSniklas 		  error_message)
619b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
6202159047fSniklas      arelent *reloc_entry;
6212159047fSniklas      asymbol *symbol;
6222159047fSniklas      PTR data;
6232159047fSniklas      asection *input_section;
6242159047fSniklas      bfd *output_bfd;
625b305b0f1Sespie      char **error_message ATTRIBUTE_UNUSED;
6262159047fSniklas {
6272159047fSniklas   bfd_reloc_status_type ret;
6282159047fSniklas   bfd_vma relocation;
6290c6d0228Sniklas   struct mips_hi *n;
6302159047fSniklas 
6312159047fSniklas   /* If we're relocating, and this an external symbol, we don't want
6322159047fSniklas      to change anything.  */
6332159047fSniklas   if (output_bfd != (bfd *) NULL
6342159047fSniklas       && (symbol->flags & BSF_SECTION_SYM) == 0
6352159047fSniklas       && reloc_entry->addend == 0)
6362159047fSniklas     {
6372159047fSniklas       reloc_entry->address += input_section->output_offset;
6382159047fSniklas       return bfd_reloc_ok;
6392159047fSniklas     }
6402159047fSniklas 
6412159047fSniklas   ret = bfd_reloc_ok;
6422159047fSniklas   if (bfd_is_und_section (symbol->section)
6432159047fSniklas       && output_bfd == (bfd *) NULL)
6442159047fSniklas     ret = bfd_reloc_undefined;
6452159047fSniklas 
6462159047fSniklas   if (bfd_is_com_section (symbol->section))
6472159047fSniklas     relocation = 0;
6482159047fSniklas   else
6492159047fSniklas     relocation = symbol->value;
6502159047fSniklas 
6512159047fSniklas   relocation += symbol->section->output_section->vma;
6522159047fSniklas   relocation += symbol->section->output_offset;
6532159047fSniklas   relocation += reloc_entry->addend;
6542159047fSniklas 
6552159047fSniklas   if (reloc_entry->address > input_section->_cooked_size)
6562159047fSniklas     return bfd_reloc_outofrange;
6572159047fSniklas 
6582159047fSniklas   /* Save the information, and let REFLO do the actual relocation.  */
659c074d1c9Sdrahn   n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
6600c6d0228Sniklas   if (n == NULL)
6610c6d0228Sniklas     return bfd_reloc_outofrange;
6620c6d0228Sniklas   n->addr = (bfd_byte *) data + reloc_entry->address;
6630c6d0228Sniklas   n->addend = relocation;
6640c6d0228Sniklas   n->next = mips_refhi_list;
6650c6d0228Sniklas   mips_refhi_list = n;
6662159047fSniklas 
6672159047fSniklas   if (output_bfd != (bfd *) NULL)
6682159047fSniklas     reloc_entry->address += input_section->output_offset;
6692159047fSniklas 
6702159047fSniklas   return ret;
6712159047fSniklas }
6722159047fSniklas 
6732159047fSniklas /* Do a REFLO relocation.  This is a straightforward 16 bit inplace
6742159047fSniklas    relocation; this function exists in order to do the REFHI
6752159047fSniklas    relocation described above.  */
6762159047fSniklas 
6772159047fSniklas static bfd_reloc_status_type
mips_reflo_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)6782159047fSniklas mips_reflo_reloc (abfd,
6792159047fSniklas 		  reloc_entry,
6802159047fSniklas 		  symbol,
6812159047fSniklas 		  data,
6822159047fSniklas 		  input_section,
6832159047fSniklas 		  output_bfd,
6842159047fSniklas 		  error_message)
6852159047fSniklas      bfd *abfd;
6862159047fSniklas      arelent *reloc_entry;
6872159047fSniklas      asymbol *symbol;
6882159047fSniklas      PTR data;
6892159047fSniklas      asection *input_section;
6902159047fSniklas      bfd *output_bfd;
6912159047fSniklas      char **error_message;
6922159047fSniklas {
6930c6d0228Sniklas   if (mips_refhi_list != NULL)
6940c6d0228Sniklas     {
6950c6d0228Sniklas       struct mips_hi *l;
6960c6d0228Sniklas 
6970c6d0228Sniklas       l = mips_refhi_list;
6980c6d0228Sniklas       while (l != NULL)
6992159047fSniklas 	{
7002159047fSniklas 	  unsigned long insn;
7012159047fSniklas 	  unsigned long val;
7022159047fSniklas 	  unsigned long vallo;
7030c6d0228Sniklas 	  struct mips_hi *next;
7042159047fSniklas 
7050c6d0228Sniklas 	  /* Do the REFHI relocation.  Note that we actually don't
7060c6d0228Sniklas 	     need to know anything about the REFLO itself, except
7070c6d0228Sniklas 	     where to find the low 16 bits of the addend needed by the
7080c6d0228Sniklas 	     REFHI.  */
7090c6d0228Sniklas 	  insn = bfd_get_32 (abfd, l->addr);
7102159047fSniklas 	  vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
7112159047fSniklas 		   & 0xffff);
7122159047fSniklas 	  val = ((insn & 0xffff) << 16) + vallo;
7130c6d0228Sniklas 	  val += l->addend;
7142159047fSniklas 
7150c6d0228Sniklas 	  /* The low order 16 bits are always treated as a signed
7160c6d0228Sniklas 	     value.  Therefore, a negative value in the low order bits
7170c6d0228Sniklas 	     requires an adjustment in the high order bits.  We need
7180c6d0228Sniklas 	     to make this adjustment in two ways: once for the bits we
7190c6d0228Sniklas 	     took from the data, and once for the bits we are putting
7200c6d0228Sniklas 	     back in to the data.  */
7212159047fSniklas 	  if ((vallo & 0x8000) != 0)
7222159047fSniklas 	    val -= 0x10000;
7232159047fSniklas 	  if ((val & 0x8000) != 0)
7242159047fSniklas 	    val += 0x10000;
7252159047fSniklas 
726c074d1c9Sdrahn 	  insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
727c074d1c9Sdrahn 	  bfd_put_32 (abfd, (bfd_vma) insn, l->addr);
7282159047fSniklas 
7290c6d0228Sniklas 	  next = l->next;
7300c6d0228Sniklas 	  free (l);
7310c6d0228Sniklas 	  l = next;
7320c6d0228Sniklas 	}
7330c6d0228Sniklas 
7340c6d0228Sniklas       mips_refhi_list = NULL;
7352159047fSniklas     }
7362159047fSniklas 
7372159047fSniklas   /* Now do the REFLO reloc in the usual way.  */
7382159047fSniklas   return mips_generic_reloc (abfd, reloc_entry, symbol, data,
7392159047fSniklas 			      input_section, output_bfd, error_message);
7402159047fSniklas }
7412159047fSniklas 
7422159047fSniklas /* Do a GPREL relocation.  This is a 16 bit value which must become
7432159047fSniklas    the offset from the gp register.  */
7442159047fSniklas 
7452159047fSniklas static bfd_reloc_status_type
mips_gprel_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)7462159047fSniklas mips_gprel_reloc (abfd,
7472159047fSniklas 		  reloc_entry,
7482159047fSniklas 		  symbol,
7492159047fSniklas 		  data,
7502159047fSniklas 		  input_section,
7512159047fSniklas 		  output_bfd,
7522159047fSniklas 		  error_message)
7532159047fSniklas      bfd *abfd;
7542159047fSniklas      arelent *reloc_entry;
7552159047fSniklas      asymbol *symbol;
7562159047fSniklas      PTR data;
7572159047fSniklas      asection *input_section;
7582159047fSniklas      bfd *output_bfd;
7592159047fSniklas      char **error_message;
7602159047fSniklas {
761*007c2a45Smiod   bfd_boolean relocatable;
762c88b1d6cSniklas   bfd_vma gp;
7632159047fSniklas   bfd_vma relocation;
7642159047fSniklas   unsigned long val;
7652159047fSniklas   unsigned long insn;
7662159047fSniklas 
7672159047fSniklas   /* If we're relocating, and this is an external symbol with no
7682159047fSniklas      addend, we don't want to change anything.  We will only have an
7692159047fSniklas      addend if this is a newly created reloc, not read from an ECOFF
7702159047fSniklas      file.  */
7712159047fSniklas   if (output_bfd != (bfd *) NULL
7722159047fSniklas       && (symbol->flags & BSF_SECTION_SYM) == 0
7732159047fSniklas       && reloc_entry->addend == 0)
7742159047fSniklas     {
7752159047fSniklas       reloc_entry->address += input_section->output_offset;
7762159047fSniklas       return bfd_reloc_ok;
7772159047fSniklas     }
7782159047fSniklas 
7792159047fSniklas   if (output_bfd != (bfd *) NULL)
780*007c2a45Smiod     relocatable = TRUE;
7812159047fSniklas   else
7822159047fSniklas     {
783*007c2a45Smiod       relocatable = FALSE;
7842159047fSniklas       output_bfd = symbol->section->output_section->owner;
7852159047fSniklas     }
7862159047fSniklas 
787*007c2a45Smiod   if (bfd_is_und_section (symbol->section) && ! relocatable)
7882159047fSniklas     return bfd_reloc_undefined;
7892159047fSniklas 
7902159047fSniklas   /* We have to figure out the gp value, so that we can adjust the
7912159047fSniklas      symbol value correctly.  We look up the symbol _gp in the output
7922159047fSniklas      BFD.  If we can't find it, we're stuck.  We cache it in the ECOFF
7932159047fSniklas      target data.  We don't need to adjust the symbol value for an
794*007c2a45Smiod      external symbol if we are producing relocatable output.  */
795c88b1d6cSniklas   gp = _bfd_get_gp_value (output_bfd);
796c88b1d6cSniklas   if (gp == 0
797*007c2a45Smiod       && (! relocatable
7982159047fSniklas 	  || (symbol->flags & BSF_SECTION_SYM) != 0))
7992159047fSniklas     {
800*007c2a45Smiod       if (relocatable)
8012159047fSniklas 	{
8022159047fSniklas 	  /* Make up a value.  */
803c88b1d6cSniklas 	  gp = symbol->section->output_section->vma + 0x4000;
804c88b1d6cSniklas 	  _bfd_set_gp_value (output_bfd, gp);
8052159047fSniklas 	}
8062159047fSniklas       else
8072159047fSniklas 	{
8082159047fSniklas 	  unsigned int count;
8092159047fSniklas 	  asymbol **sym;
8102159047fSniklas 	  unsigned int i;
8112159047fSniklas 
8122159047fSniklas 	  count = bfd_get_symcount (output_bfd);
8132159047fSniklas 	  sym = bfd_get_outsymbols (output_bfd);
8142159047fSniklas 
8152159047fSniklas 	  if (sym == (asymbol **) NULL)
8162159047fSniklas 	    i = count;
8172159047fSniklas 	  else
8182159047fSniklas 	    {
8192159047fSniklas 	      for (i = 0; i < count; i++, sym++)
8202159047fSniklas 		{
821c074d1c9Sdrahn 		  register const char *name;
8222159047fSniklas 
8232159047fSniklas 		  name = bfd_asymbol_name (*sym);
8242159047fSniklas 		  if (*name == '_' && strcmp (name, "_gp") == 0)
8252159047fSniklas 		    {
826c88b1d6cSniklas 		      gp = bfd_asymbol_value (*sym);
827c88b1d6cSniklas 		      _bfd_set_gp_value (output_bfd, gp);
8282159047fSniklas 		      break;
8292159047fSniklas 		    }
8302159047fSniklas 		}
8312159047fSniklas 	    }
8322159047fSniklas 
8332159047fSniklas 	  if (i >= count)
8342159047fSniklas 	    {
8352159047fSniklas 	      /* Only get the error once.  */
836c88b1d6cSniklas 	      gp = 4;
837c88b1d6cSniklas 	      _bfd_set_gp_value (output_bfd, gp);
8382159047fSniklas 	      *error_message =
839b305b0f1Sespie 		(char *) _("GP relative relocation when _gp not defined");
8402159047fSniklas 	      return bfd_reloc_dangerous;
8412159047fSniklas 	    }
8422159047fSniklas 	}
8432159047fSniklas     }
8442159047fSniklas 
8452159047fSniklas   if (bfd_is_com_section (symbol->section))
8462159047fSniklas     relocation = 0;
8472159047fSniklas   else
8482159047fSniklas     relocation = symbol->value;
8492159047fSniklas 
8502159047fSniklas   relocation += symbol->section->output_section->vma;
8512159047fSniklas   relocation += symbol->section->output_offset;
8522159047fSniklas 
8532159047fSniklas   if (reloc_entry->address > input_section->_cooked_size)
8542159047fSniklas     return bfd_reloc_outofrange;
8552159047fSniklas 
8562159047fSniklas   insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
8572159047fSniklas 
8582159047fSniklas   /* Set val to the offset into the section or symbol.  */
8592159047fSniklas   val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
8602159047fSniklas   if (val & 0x8000)
8612159047fSniklas     val -= 0x10000;
8622159047fSniklas 
8632159047fSniklas   /* Adjust val for the final section location and GP value.  If we
864*007c2a45Smiod      are producing relocatable output, we don't want to do this for
8652159047fSniklas      an external symbol.  */
866*007c2a45Smiod   if (! relocatable
8672159047fSniklas       || (symbol->flags & BSF_SECTION_SYM) != 0)
868c88b1d6cSniklas     val += relocation - gp;
8692159047fSniklas 
870c074d1c9Sdrahn   insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff);
871c074d1c9Sdrahn   bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);
8722159047fSniklas 
873*007c2a45Smiod   if (relocatable)
8742159047fSniklas     reloc_entry->address += input_section->output_offset;
8752159047fSniklas 
8762159047fSniklas   /* Make sure it fit in 16 bits.  */
877b55d4692Sfgsch   if ((long) val >= 0x8000 || (long) val < -0x8000)
8782159047fSniklas     return bfd_reloc_overflow;
8792159047fSniklas 
8802159047fSniklas   return bfd_reloc_ok;
8812159047fSniklas }
8822159047fSniklas 
8832159047fSniklas /* Do a RELHI relocation.  We do this in conjunction with a RELLO
8842159047fSniklas    reloc, just as REFHI and REFLO are done together.  RELHI and RELLO
8852159047fSniklas    are Cygnus extensions used when generating position independent
8862159047fSniklas    code for embedded systems.  */
8872159047fSniklas 
8880c6d0228Sniklas /* FIXME: This should not be a static variable.  */
8890c6d0228Sniklas 
8900c6d0228Sniklas static struct mips_hi *mips_relhi_list;
8912159047fSniklas 
8922159047fSniklas static bfd_reloc_status_type
mips_relhi_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)8932159047fSniklas mips_relhi_reloc (abfd,
8942159047fSniklas 		  reloc_entry,
8952159047fSniklas 		  symbol,
8962159047fSniklas 		  data,
8972159047fSniklas 		  input_section,
8982159047fSniklas 		  output_bfd,
8992159047fSniklas 		  error_message)
900b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
9012159047fSniklas      arelent *reloc_entry;
9022159047fSniklas      asymbol *symbol;
9032159047fSniklas      PTR data;
9042159047fSniklas      asection *input_section;
9052159047fSniklas      bfd *output_bfd;
906b305b0f1Sespie      char **error_message ATTRIBUTE_UNUSED;
9072159047fSniklas {
9082159047fSniklas   bfd_reloc_status_type ret;
9092159047fSniklas   bfd_vma relocation;
9100c6d0228Sniklas   struct mips_hi *n;
9112159047fSniklas 
9122159047fSniklas   /* If this is a reloc against a section symbol, then it is correct
9132159047fSniklas      in the object file.  The only time we want to change this case is
9142159047fSniklas      when we are relaxing, and that is handled entirely by
9152159047fSniklas      mips_relocate_section and never calls this function.  */
9162159047fSniklas   if ((symbol->flags & BSF_SECTION_SYM) != 0)
9172159047fSniklas     {
9182159047fSniklas       if (output_bfd != (bfd *) NULL)
9192159047fSniklas 	reloc_entry->address += input_section->output_offset;
9202159047fSniklas       return bfd_reloc_ok;
9212159047fSniklas     }
9222159047fSniklas 
9232159047fSniklas   /* This is an external symbol.  If we're relocating, we don't want
9242159047fSniklas      to change anything.  */
9252159047fSniklas   if (output_bfd != (bfd *) NULL)
9262159047fSniklas     {
9272159047fSniklas       reloc_entry->address += input_section->output_offset;
9282159047fSniklas       return bfd_reloc_ok;
9292159047fSniklas     }
9302159047fSniklas 
9312159047fSniklas   ret = bfd_reloc_ok;
9322159047fSniklas   if (bfd_is_und_section (symbol->section)
9332159047fSniklas       && output_bfd == (bfd *) NULL)
9342159047fSniklas     ret = bfd_reloc_undefined;
9352159047fSniklas 
9362159047fSniklas   if (bfd_is_com_section (symbol->section))
9372159047fSniklas     relocation = 0;
9382159047fSniklas   else
9392159047fSniklas     relocation = symbol->value;
9402159047fSniklas 
9412159047fSniklas   relocation += symbol->section->output_section->vma;
9422159047fSniklas   relocation += symbol->section->output_offset;
9432159047fSniklas   relocation += reloc_entry->addend;
9442159047fSniklas 
9452159047fSniklas   if (reloc_entry->address > input_section->_cooked_size)
9462159047fSniklas     return bfd_reloc_outofrange;
9472159047fSniklas 
9482159047fSniklas   /* Save the information, and let RELLO do the actual relocation.  */
949c074d1c9Sdrahn   n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
9500c6d0228Sniklas   if (n == NULL)
9510c6d0228Sniklas     return bfd_reloc_outofrange;
9520c6d0228Sniklas   n->addr = (bfd_byte *) data + reloc_entry->address;
9530c6d0228Sniklas   n->addend = relocation;
9540c6d0228Sniklas   n->next = mips_relhi_list;
9550c6d0228Sniklas   mips_relhi_list = n;
9562159047fSniklas 
9572159047fSniklas   if (output_bfd != (bfd *) NULL)
9582159047fSniklas     reloc_entry->address += input_section->output_offset;
9592159047fSniklas 
9602159047fSniklas   return ret;
9612159047fSniklas }
9622159047fSniklas 
9632159047fSniklas /* Do a RELLO relocation.  This is a straightforward 16 bit PC
9642159047fSniklas    relative relocation; this function exists in order to do the RELHI
9652159047fSniklas    relocation described above.  */
9662159047fSniklas 
9672159047fSniklas static bfd_reloc_status_type
mips_rello_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)9682159047fSniklas mips_rello_reloc (abfd,
9692159047fSniklas 		  reloc_entry,
9702159047fSniklas 		  symbol,
9712159047fSniklas 		  data,
9722159047fSniklas 		  input_section,
9732159047fSniklas 		  output_bfd,
9742159047fSniklas 		  error_message)
9752159047fSniklas      bfd *abfd;
9762159047fSniklas      arelent *reloc_entry;
9772159047fSniklas      asymbol *symbol;
9782159047fSniklas      PTR data;
9792159047fSniklas      asection *input_section;
9802159047fSniklas      bfd *output_bfd;
9812159047fSniklas      char **error_message;
9822159047fSniklas {
9830c6d0228Sniklas   if (mips_relhi_list != NULL)
9840c6d0228Sniklas     {
9850c6d0228Sniklas       struct mips_hi *l;
9860c6d0228Sniklas 
9870c6d0228Sniklas       l = mips_relhi_list;
9880c6d0228Sniklas       while (l != NULL)
9892159047fSniklas 	{
9902159047fSniklas 	  unsigned long insn;
9912159047fSniklas 	  unsigned long val;
9922159047fSniklas 	  unsigned long vallo;
9930c6d0228Sniklas 	  struct mips_hi *next;
9942159047fSniklas 
9950c6d0228Sniklas 	  /* Do the RELHI relocation.  Note that we actually don't
9960c6d0228Sniklas 	     need to know anything about the RELLO itself, except
9970c6d0228Sniklas 	     where to find the low 16 bits of the addend needed by the
9980c6d0228Sniklas 	     RELHI.  */
9990c6d0228Sniklas 	  insn = bfd_get_32 (abfd, l->addr);
10002159047fSniklas 	  vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
10012159047fSniklas 		   & 0xffff);
10022159047fSniklas 	  val = ((insn & 0xffff) << 16) + vallo;
10030c6d0228Sniklas 	  val += l->addend;
10042159047fSniklas 
10052159047fSniklas 	  /* If the symbol is defined, make val PC relative.  If the
10060c6d0228Sniklas 	     symbol is not defined we don't want to do this, because
10070c6d0228Sniklas 	     we don't want the value in the object file to incorporate
10080c6d0228Sniklas 	     the address of the reloc.  */
10092159047fSniklas 	  if (! bfd_is_und_section (bfd_get_section (symbol))
10102159047fSniklas 	      && ! bfd_is_com_section (bfd_get_section (symbol)))
10112159047fSniklas 	    val -= (input_section->output_section->vma
10122159047fSniklas 		    + input_section->output_offset
10132159047fSniklas 		    + reloc_entry->address);
10142159047fSniklas 
10150c6d0228Sniklas 	  /* The low order 16 bits are always treated as a signed
10160c6d0228Sniklas 	     value.  Therefore, a negative value in the low order bits
10170c6d0228Sniklas 	     requires an adjustment in the high order bits.  We need
10180c6d0228Sniklas 	     to make this adjustment in two ways: once for the bits we
10190c6d0228Sniklas 	     took from the data, and once for the bits we are putting
10200c6d0228Sniklas 	     back in to the data.  */
10212159047fSniklas 	  if ((vallo & 0x8000) != 0)
10222159047fSniklas 	    val -= 0x10000;
10232159047fSniklas 	  if ((val & 0x8000) != 0)
10242159047fSniklas 	    val += 0x10000;
10252159047fSniklas 
1026c074d1c9Sdrahn 	  insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
1027c074d1c9Sdrahn 	  bfd_put_32 (abfd, (bfd_vma) insn, l->addr);
10282159047fSniklas 
10290c6d0228Sniklas 	  next = l->next;
10300c6d0228Sniklas 	  free (l);
10310c6d0228Sniklas 	  l = next;
10320c6d0228Sniklas 	}
10330c6d0228Sniklas 
10340c6d0228Sniklas       mips_relhi_list = NULL;
10352159047fSniklas     }
10362159047fSniklas 
10372159047fSniklas   /* If this is a reloc against a section symbol, then it is correct
10382159047fSniklas      in the object file.  The only time we want to change this case is
10392159047fSniklas      when we are relaxing, and that is handled entirely by
10402159047fSniklas      mips_relocate_section and never calls this function.  */
10412159047fSniklas   if ((symbol->flags & BSF_SECTION_SYM) != 0)
10422159047fSniklas     {
10432159047fSniklas       if (output_bfd != (bfd *) NULL)
10442159047fSniklas 	reloc_entry->address += input_section->output_offset;
10452159047fSniklas       return bfd_reloc_ok;
10462159047fSniklas     }
10472159047fSniklas 
10482159047fSniklas   /* bfd_perform_relocation does not handle pcrel_offset relocations
1049*007c2a45Smiod      correctly when generating a relocatable file, so handle them
10502159047fSniklas      directly here.  */
10512159047fSniklas   if (output_bfd != (bfd *) NULL)
10522159047fSniklas     {
10532159047fSniklas       reloc_entry->address += input_section->output_offset;
10542159047fSniklas       return bfd_reloc_ok;
10552159047fSniklas     }
10562159047fSniklas 
10572159047fSniklas   /* Now do the RELLO reloc in the usual way.  */
10582159047fSniklas   return mips_generic_reloc (abfd, reloc_entry, symbol, data,
10592159047fSniklas 			      input_section, output_bfd, error_message);
10602159047fSniklas }
10612159047fSniklas 
10622159047fSniklas /* This is the special function for the MIPS_R_SWITCH reloc.  This
10632159047fSniklas    special reloc is normally correct in the object file, and only
10642159047fSniklas    requires special handling when relaxing.  We don't want
10652159047fSniklas    bfd_perform_relocation to tamper with it at all.  */
10662159047fSniklas 
10672159047fSniklas static bfd_reloc_status_type
mips_switch_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)10682159047fSniklas mips_switch_reloc (abfd,
10692159047fSniklas 		   reloc_entry,
10702159047fSniklas 		   symbol,
10712159047fSniklas 		   data,
10722159047fSniklas 		   input_section,
10732159047fSniklas 		   output_bfd,
10742159047fSniklas 		   error_message)
1075b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
1076b305b0f1Sespie      arelent *reloc_entry ATTRIBUTE_UNUSED;
1077b305b0f1Sespie      asymbol *symbol ATTRIBUTE_UNUSED;
1078b305b0f1Sespie      PTR data ATTRIBUTE_UNUSED;
1079b305b0f1Sespie      asection *input_section ATTRIBUTE_UNUSED;
1080b305b0f1Sespie      bfd *output_bfd ATTRIBUTE_UNUSED;
1081b305b0f1Sespie      char **error_message ATTRIBUTE_UNUSED;
10822159047fSniklas {
10832159047fSniklas   return bfd_reloc_ok;
10842159047fSniklas }
10852159047fSniklas 
10862159047fSniklas /* Get the howto structure for a generic reloc type.  */
10872159047fSniklas 
10882159047fSniklas static reloc_howto_type *
mips_bfd_reloc_type_lookup(abfd,code)10892159047fSniklas mips_bfd_reloc_type_lookup (abfd, code)
1090b305b0f1Sespie      bfd *abfd ATTRIBUTE_UNUSED;
10912159047fSniklas      bfd_reloc_code_real_type code;
10922159047fSniklas {
10932159047fSniklas   int mips_type;
10942159047fSniklas 
10952159047fSniklas   switch (code)
10962159047fSniklas     {
10972159047fSniklas     case BFD_RELOC_16:
10982159047fSniklas       mips_type = MIPS_R_REFHALF;
10992159047fSniklas       break;
11002159047fSniklas     case BFD_RELOC_32:
11012159047fSniklas     case BFD_RELOC_CTOR:
11022159047fSniklas       mips_type = MIPS_R_REFWORD;
11032159047fSniklas       break;
11042159047fSniklas     case BFD_RELOC_MIPS_JMP:
11052159047fSniklas       mips_type = MIPS_R_JMPADDR;
11062159047fSniklas       break;
11072159047fSniklas     case BFD_RELOC_HI16_S:
11082159047fSniklas       mips_type = MIPS_R_REFHI;
11092159047fSniklas       break;
11102159047fSniklas     case BFD_RELOC_LO16:
11112159047fSniklas       mips_type = MIPS_R_REFLO;
11122159047fSniklas       break;
1113c074d1c9Sdrahn     case BFD_RELOC_GPREL16:
11142159047fSniklas       mips_type = MIPS_R_GPREL;
11152159047fSniklas       break;
11162159047fSniklas     case BFD_RELOC_MIPS_LITERAL:
11172159047fSniklas       mips_type = MIPS_R_LITERAL;
11182159047fSniklas       break;
11192159047fSniklas     case BFD_RELOC_16_PCREL_S2:
11202159047fSniklas       mips_type = MIPS_R_PCREL16;
11212159047fSniklas       break;
11222159047fSniklas     case BFD_RELOC_PCREL_HI16_S:
11232159047fSniklas       mips_type = MIPS_R_RELHI;
11242159047fSniklas       break;
11252159047fSniklas     case BFD_RELOC_PCREL_LO16:
11262159047fSniklas       mips_type = MIPS_R_RELLO;
11272159047fSniklas       break;
11282159047fSniklas     case BFD_RELOC_GPREL32:
11292159047fSniklas       mips_type = MIPS_R_SWITCH;
11302159047fSniklas       break;
11312159047fSniklas     default:
11322159047fSniklas       return (reloc_howto_type *) NULL;
11332159047fSniklas     }
11342159047fSniklas 
11352159047fSniklas   return &mips_howto_table[mips_type];
11362159047fSniklas }
11372159047fSniklas 
11382159047fSniklas /* A helper routine for mips_relocate_section which handles the REFHI
11392159047fSniklas    and RELHI relocations.  The REFHI relocation must be followed by a
11402159047fSniklas    REFLO relocation (and RELHI by a RELLO), and the addend used is
11412159047fSniklas    formed from the addends of both instructions.  */
11422159047fSniklas 
11432159047fSniklas static void
mips_relocate_hi(refhi,reflo,input_bfd,input_section,contents,adjust,relocation,pcrel)11442159047fSniklas mips_relocate_hi (refhi, reflo, input_bfd, input_section, contents, adjust,
11452159047fSniklas 		  relocation, pcrel)
11462159047fSniklas      struct internal_reloc *refhi;
11472159047fSniklas      struct internal_reloc *reflo;
11482159047fSniklas      bfd *input_bfd;
11492159047fSniklas      asection *input_section;
11502159047fSniklas      bfd_byte *contents;
11512159047fSniklas      size_t adjust;
11522159047fSniklas      bfd_vma relocation;
1153c074d1c9Sdrahn      bfd_boolean pcrel;
11542159047fSniklas {
11552159047fSniklas   unsigned long insn;
11562159047fSniklas   unsigned long val;
11572159047fSniklas   unsigned long vallo;
11582159047fSniklas 
1159b305b0f1Sespie   if (refhi == NULL)
1160b305b0f1Sespie     return;
1161b305b0f1Sespie 
11622159047fSniklas   insn = bfd_get_32 (input_bfd,
11632159047fSniklas 		     contents + adjust + refhi->r_vaddr - input_section->vma);
1164b305b0f1Sespie   if (reflo == NULL)
1165b305b0f1Sespie     vallo = 0;
1166b305b0f1Sespie   else
11672159047fSniklas     vallo = (bfd_get_32 (input_bfd,
11682159047fSniklas 			 contents + adjust + reflo->r_vaddr - input_section->vma)
11692159047fSniklas 	     & 0xffff);
1170b305b0f1Sespie 
11712159047fSniklas   val = ((insn & 0xffff) << 16) + vallo;
11722159047fSniklas   val += relocation;
11732159047fSniklas 
11742159047fSniklas   /* The low order 16 bits are always treated as a signed value.
11752159047fSniklas      Therefore, a negative value in the low order bits requires an
11762159047fSniklas      adjustment in the high order bits.  We need to make this
11772159047fSniklas      adjustment in two ways: once for the bits we took from the data,
11782159047fSniklas      and once for the bits we are putting back in to the data.  */
11792159047fSniklas   if ((vallo & 0x8000) != 0)
11802159047fSniklas     val -= 0x10000;
11812159047fSniklas 
11822159047fSniklas   if (pcrel)
11832159047fSniklas     val -= (input_section->output_section->vma
11842159047fSniklas 	    + input_section->output_offset
11852159047fSniklas 	    + (reflo->r_vaddr - input_section->vma + adjust));
11862159047fSniklas 
11872159047fSniklas   if ((val & 0x8000) != 0)
11882159047fSniklas     val += 0x10000;
11892159047fSniklas 
1190c074d1c9Sdrahn   insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
11912159047fSniklas   bfd_put_32 (input_bfd, (bfd_vma) insn,
11922159047fSniklas 	      contents + adjust + refhi->r_vaddr - input_section->vma);
11932159047fSniklas }
11942159047fSniklas 
11952159047fSniklas /* Relocate a section while linking a MIPS ECOFF file.  */
11962159047fSniklas 
1197c074d1c9Sdrahn static bfd_boolean
mips_relocate_section(output_bfd,info,input_bfd,input_section,contents,external_relocs)11982159047fSniklas mips_relocate_section (output_bfd, info, input_bfd, input_section,
11992159047fSniklas 		       contents, external_relocs)
12002159047fSniklas      bfd *output_bfd;
12012159047fSniklas      struct bfd_link_info *info;
12022159047fSniklas      bfd *input_bfd;
12032159047fSniklas      asection *input_section;
12042159047fSniklas      bfd_byte *contents;
12052159047fSniklas      PTR external_relocs;
12062159047fSniklas {
12072159047fSniklas   asection **symndx_to_section;
12082159047fSniklas   struct ecoff_link_hash_entry **sym_hashes;
12092159047fSniklas   bfd_vma gp;
1210c074d1c9Sdrahn   bfd_boolean gp_undefined;
12112159047fSniklas   size_t adjust;
12122159047fSniklas   long *offsets;
12132159047fSniklas   struct external_reloc *ext_rel;
12142159047fSniklas   struct external_reloc *ext_rel_end;
12152159047fSniklas   unsigned int i;
1216c074d1c9Sdrahn   bfd_boolean got_lo;
12172159047fSniklas   struct internal_reloc lo_int_rel;
1218c074d1c9Sdrahn   bfd_size_type amt;
12192159047fSniklas 
1220b305b0f1Sespie   BFD_ASSERT (input_bfd->xvec->byteorder
1221b305b0f1Sespie 	      == output_bfd->xvec->byteorder);
12222159047fSniklas 
12232159047fSniklas   /* We keep a table mapping the symndx found in an internal reloc to
12242159047fSniklas      the appropriate section.  This is faster than looking up the
12252159047fSniklas      section by name each time.  */
12262159047fSniklas   symndx_to_section = ecoff_data (input_bfd)->symndx_to_section;
12272159047fSniklas   if (symndx_to_section == (asection **) NULL)
12282159047fSniklas     {
1229c074d1c9Sdrahn       amt = NUM_RELOC_SECTIONS * sizeof (asection *);
1230c074d1c9Sdrahn       symndx_to_section = (asection **) bfd_alloc (input_bfd, amt);
12312159047fSniklas       if (!symndx_to_section)
1232c074d1c9Sdrahn 	return FALSE;
12332159047fSniklas 
12342159047fSniklas       symndx_to_section[RELOC_SECTION_NONE] = NULL;
12352159047fSniklas       symndx_to_section[RELOC_SECTION_TEXT] =
12362159047fSniklas 	bfd_get_section_by_name (input_bfd, ".text");
12372159047fSniklas       symndx_to_section[RELOC_SECTION_RDATA] =
12382159047fSniklas 	bfd_get_section_by_name (input_bfd, ".rdata");
12392159047fSniklas       symndx_to_section[RELOC_SECTION_DATA] =
12402159047fSniklas 	bfd_get_section_by_name (input_bfd, ".data");
12412159047fSniklas       symndx_to_section[RELOC_SECTION_SDATA] =
12422159047fSniklas 	bfd_get_section_by_name (input_bfd, ".sdata");
12432159047fSniklas       symndx_to_section[RELOC_SECTION_SBSS] =
12442159047fSniklas 	bfd_get_section_by_name (input_bfd, ".sbss");
12452159047fSniklas       symndx_to_section[RELOC_SECTION_BSS] =
12462159047fSniklas 	bfd_get_section_by_name (input_bfd, ".bss");
12472159047fSniklas       symndx_to_section[RELOC_SECTION_INIT] =
12482159047fSniklas 	bfd_get_section_by_name (input_bfd, ".init");
12492159047fSniklas       symndx_to_section[RELOC_SECTION_LIT8] =
12502159047fSniklas 	bfd_get_section_by_name (input_bfd, ".lit8");
12512159047fSniklas       symndx_to_section[RELOC_SECTION_LIT4] =
12522159047fSniklas 	bfd_get_section_by_name (input_bfd, ".lit4");
12532159047fSniklas       symndx_to_section[RELOC_SECTION_XDATA] = NULL;
12542159047fSniklas       symndx_to_section[RELOC_SECTION_PDATA] = NULL;
12552159047fSniklas       symndx_to_section[RELOC_SECTION_FINI] =
12562159047fSniklas 	bfd_get_section_by_name (input_bfd, ".fini");
12572159047fSniklas       symndx_to_section[RELOC_SECTION_LITA] = NULL;
12582159047fSniklas       symndx_to_section[RELOC_SECTION_ABS] = NULL;
12592159047fSniklas 
12602159047fSniklas       ecoff_data (input_bfd)->symndx_to_section = symndx_to_section;
12612159047fSniklas     }
12622159047fSniklas 
12632159047fSniklas   sym_hashes = ecoff_data (input_bfd)->sym_hashes;
12642159047fSniklas 
1265c88b1d6cSniklas   gp = _bfd_get_gp_value (output_bfd);
12662159047fSniklas   if (gp == 0)
1267c074d1c9Sdrahn     gp_undefined = TRUE;
12682159047fSniklas   else
1269c074d1c9Sdrahn     gp_undefined = FALSE;
12702159047fSniklas 
1271c074d1c9Sdrahn   got_lo = FALSE;
12722159047fSniklas 
12732159047fSniklas   adjust = 0;
12742159047fSniklas 
12752159047fSniklas   if (ecoff_section_data (input_bfd, input_section) == NULL)
12762159047fSniklas     offsets = NULL;
12772159047fSniklas   else
12782159047fSniklas     offsets = ecoff_section_data (input_bfd, input_section)->offsets;
12792159047fSniklas 
12802159047fSniklas   ext_rel = (struct external_reloc *) external_relocs;
12812159047fSniklas   ext_rel_end = ext_rel + input_section->reloc_count;
12822159047fSniklas   for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
12832159047fSniklas     {
12842159047fSniklas       struct internal_reloc int_rel;
1285c074d1c9Sdrahn       bfd_boolean use_lo = FALSE;
12862159047fSniklas       bfd_vma addend;
12872159047fSniklas       reloc_howto_type *howto;
12882159047fSniklas       struct ecoff_link_hash_entry *h = NULL;
12892159047fSniklas       asection *s = NULL;
12902159047fSniklas       bfd_vma relocation;
12912159047fSniklas       bfd_reloc_status_type r;
12922159047fSniklas 
12932159047fSniklas       if (! got_lo)
12942159047fSniklas 	mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel);
12952159047fSniklas       else
12962159047fSniklas 	{
12972159047fSniklas 	  int_rel = lo_int_rel;
1298c074d1c9Sdrahn 	  got_lo = FALSE;
12992159047fSniklas 	}
13002159047fSniklas 
13012159047fSniklas       BFD_ASSERT (int_rel.r_type
13022159047fSniklas 		  < sizeof mips_howto_table / sizeof mips_howto_table[0]);
13032159047fSniklas 
13042159047fSniklas       /* The REFHI and RELHI relocs requires special handling.  they
13052159047fSniklas 	 must be followed by a REFLO or RELLO reloc, respectively, and
13062159047fSniklas 	 the addend is formed from both relocs.  */
13072159047fSniklas       if (int_rel.r_type == MIPS_R_REFHI
13082159047fSniklas 	  || int_rel.r_type == MIPS_R_RELHI)
13092159047fSniklas 	{
13100c6d0228Sniklas 	  struct external_reloc *lo_ext_rel;
13110c6d0228Sniklas 
13120c6d0228Sniklas 	  /* As a GNU extension, permit an arbitrary number of REFHI
13130c6d0228Sniklas              or RELHI relocs before the REFLO or RELLO reloc.  This
13140c6d0228Sniklas              permits gcc to emit the HI and LO relocs itself.  */
13150c6d0228Sniklas 	  for (lo_ext_rel = ext_rel + 1;
13160c6d0228Sniklas 	       lo_ext_rel < ext_rel_end;
13170c6d0228Sniklas 	       lo_ext_rel++)
13180c6d0228Sniklas 	    {
13190c6d0228Sniklas 	      mips_ecoff_swap_reloc_in (input_bfd, (PTR) lo_ext_rel,
13202159047fSniklas 					&lo_int_rel);
13210c6d0228Sniklas 	      if (lo_int_rel.r_type != int_rel.r_type)
13220c6d0228Sniklas 		break;
13230c6d0228Sniklas 	    }
13240c6d0228Sniklas 
13250c6d0228Sniklas 	  if (lo_ext_rel < ext_rel_end
13260c6d0228Sniklas 	      && (lo_int_rel.r_type
13272159047fSniklas 		  == (int_rel.r_type == MIPS_R_REFHI
13282159047fSniklas 		      ? MIPS_R_REFLO
13292159047fSniklas 		      : MIPS_R_RELLO))
13302159047fSniklas 	      && int_rel.r_extern == lo_int_rel.r_extern
13310c6d0228Sniklas 	      && int_rel.r_symndx == lo_int_rel.r_symndx)
13320c6d0228Sniklas 	    {
1333c074d1c9Sdrahn 	      use_lo = TRUE;
13340c6d0228Sniklas 	      if (lo_ext_rel == ext_rel + 1)
1335c074d1c9Sdrahn 		got_lo = TRUE;
13362159047fSniklas 	    }
13370c6d0228Sniklas 	}
13382159047fSniklas 
13392159047fSniklas       howto = &mips_howto_table[int_rel.r_type];
13402159047fSniklas 
13412159047fSniklas       /* The SWITCH reloc must be handled specially.  This reloc is
13422159047fSniklas 	 marks the location of a difference between two portions of an
13432159047fSniklas 	 object file.  The symbol index does not reference a symbol,
13442159047fSniklas 	 but is actually the offset from the reloc to the subtrahend
13452159047fSniklas 	 of the difference.  This reloc is correct in the object file,
13462159047fSniklas 	 and needs no further adjustment, unless we are relaxing.  If
13472159047fSniklas 	 we are relaxing, we may have to add in an offset.  Since no
13482159047fSniklas 	 symbols are involved in this reloc, we handle it completely
13492159047fSniklas 	 here.  */
13502159047fSniklas       if (int_rel.r_type == MIPS_R_SWITCH)
13512159047fSniklas 	{
13522159047fSniklas 	  if (offsets != NULL
13532159047fSniklas 	      && offsets[i] != 0)
13542159047fSniklas 	    {
13552159047fSniklas 	      r = _bfd_relocate_contents (howto, input_bfd,
13562159047fSniklas 					  (bfd_vma) offsets[i],
13572159047fSniklas 					  (contents
13582159047fSniklas 					   + adjust
13592159047fSniklas 					   + int_rel.r_vaddr
13602159047fSniklas 					   - input_section->vma));
13612159047fSniklas 	      BFD_ASSERT (r == bfd_reloc_ok);
13622159047fSniklas 	    }
13632159047fSniklas 
13642159047fSniklas 	  continue;
13652159047fSniklas 	}
13662159047fSniklas 
13672159047fSniklas       if (int_rel.r_extern)
13682159047fSniklas 	{
13692159047fSniklas 	  h = sym_hashes[int_rel.r_symndx];
13702159047fSniklas 	  /* If h is NULL, that means that there is a reloc against an
13712159047fSniklas 	     external symbol which we thought was just a debugging
13722159047fSniklas 	     symbol.  This should not happen.  */
13732159047fSniklas 	  if (h == (struct ecoff_link_hash_entry *) NULL)
13742159047fSniklas 	    abort ();
13752159047fSniklas 	}
13762159047fSniklas       else
13772159047fSniklas 	{
13782159047fSniklas 	  if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS)
13792159047fSniklas 	    s = NULL;
13802159047fSniklas 	  else
13812159047fSniklas 	    s = symndx_to_section[int_rel.r_symndx];
13822159047fSniklas 
13832159047fSniklas 	  if (s == (asection *) NULL)
13842159047fSniklas 	    abort ();
13852159047fSniklas 	}
13862159047fSniklas 
13872159047fSniklas       /* The GPREL reloc uses an addend: the difference in the GP
13882159047fSniklas 	 values.  */
13892159047fSniklas       if (int_rel.r_type != MIPS_R_GPREL
13902159047fSniklas 	  && int_rel.r_type != MIPS_R_LITERAL)
13912159047fSniklas 	addend = 0;
13922159047fSniklas       else
13932159047fSniklas 	{
13942159047fSniklas 	  if (gp_undefined)
13952159047fSniklas 	    {
13962159047fSniklas 	      if (! ((*info->callbacks->reloc_dangerous)
1397c074d1c9Sdrahn 		     (info, _("GP relative relocation used when GP not defined"),
13982159047fSniklas 		      input_bfd, input_section,
13992159047fSniklas 		      int_rel.r_vaddr - input_section->vma)))
1400c074d1c9Sdrahn 		return FALSE;
14012159047fSniklas 	      /* Only give the error once per link.  */
1402c88b1d6cSniklas 	      gp = 4;
1403c88b1d6cSniklas 	      _bfd_set_gp_value (output_bfd, gp);
1404c074d1c9Sdrahn 	      gp_undefined = FALSE;
14052159047fSniklas 	    }
14062159047fSniklas 	  if (! int_rel.r_extern)
14072159047fSniklas 	    {
14082159047fSniklas 	      /* This is a relocation against a section.  The current
14092159047fSniklas 		 addend in the instruction is the difference between
14102159047fSniklas 		 INPUT_SECTION->vma and the GP value of INPUT_BFD.  We
14112159047fSniklas 		 must change this to be the difference between the
14122159047fSniklas 		 final definition (which will end up in RELOCATION)
14132159047fSniklas 		 and the GP value of OUTPUT_BFD (which is in GP).  */
14142159047fSniklas 	      addend = ecoff_data (input_bfd)->gp - gp;
14152159047fSniklas 	    }
1416*007c2a45Smiod 	  else if (! info->relocatable
14172159047fSniklas 		   || h->root.type == bfd_link_hash_defined
14182159047fSniklas 		   || h->root.type == bfd_link_hash_defweak)
14192159047fSniklas 	    {
14202159047fSniklas 	      /* This is a relocation against a defined symbol.  The
14212159047fSniklas 		 current addend in the instruction is simply the
14222159047fSniklas 		 desired offset into the symbol (normally zero).  We
14232159047fSniklas 		 are going to change this into a relocation against a
14242159047fSniklas 		 defined symbol, so we want the instruction to hold
14252159047fSniklas 		 the difference between the final definition of the
14262159047fSniklas 		 symbol (which will end up in RELOCATION) and the GP
14272159047fSniklas 		 value of OUTPUT_BFD (which is in GP).  */
14282159047fSniklas 	      addend = - gp;
14292159047fSniklas 	    }
14302159047fSniklas 	  else
14312159047fSniklas 	    {
14322159047fSniklas 	      /* This is a relocation against an undefined or common
14332159047fSniklas 		 symbol.  The current addend in the instruction is
14342159047fSniklas 		 simply the desired offset into the symbol (normally
1435*007c2a45Smiod 		 zero).  We are generating relocatable output, and we
14362159047fSniklas 		 aren't going to define this symbol, so we just leave
14372159047fSniklas 		 the instruction alone.  */
14382159047fSniklas 	      addend = 0;
14392159047fSniklas 	    }
14402159047fSniklas 	}
14412159047fSniklas 
14422159047fSniklas       /* If we are relaxing, mips_relax_section may have set
14432159047fSniklas 	 offsets[i] to some value.  A value of 1 means we must expand
14442159047fSniklas 	 a PC relative branch into a multi-instruction of sequence,
14452159047fSniklas 	 and any other value is an addend.  */
14462159047fSniklas       if (offsets != NULL
14472159047fSniklas 	  && offsets[i] != 0)
14482159047fSniklas 	{
1449*007c2a45Smiod 	  BFD_ASSERT (! info->relocatable);
14502159047fSniklas 	  BFD_ASSERT (int_rel.r_type == MIPS_R_PCREL16
14512159047fSniklas 		      || int_rel.r_type == MIPS_R_RELHI
14522159047fSniklas 		      || int_rel.r_type == MIPS_R_RELLO);
14532159047fSniklas 	  if (offsets[i] != 1)
14542159047fSniklas 	    addend += offsets[i];
14552159047fSniklas 	  else
14562159047fSniklas 	    {
14572159047fSniklas 	      bfd_byte *here;
14582159047fSniklas 
14592159047fSniklas 	      BFD_ASSERT (int_rel.r_extern
14602159047fSniklas 			  && int_rel.r_type == MIPS_R_PCREL16);
14612159047fSniklas 
14622159047fSniklas 	      /* Move the rest of the instructions up.  */
14632159047fSniklas 	      here = (contents
14642159047fSniklas 		      + adjust
14652159047fSniklas 		      + int_rel.r_vaddr
14662159047fSniklas 		      - input_section->vma);
14672159047fSniklas 	      memmove (here + PCREL16_EXPANSION_ADJUSTMENT, here,
14682159047fSniklas 		       (size_t) (input_section->_raw_size
14692159047fSniklas 				 - (int_rel.r_vaddr - input_section->vma)));
14702159047fSniklas 
14712159047fSniklas 	      /* Generate the new instructions.  */
14722159047fSniklas 	      if (! mips_relax_pcrel16 (info, input_bfd, input_section,
14732159047fSniklas 					h, here,
14742159047fSniklas 					(input_section->output_section->vma
14752159047fSniklas 					 + input_section->output_offset
14762159047fSniklas 					 + (int_rel.r_vaddr
14772159047fSniklas 					    - input_section->vma)
14782159047fSniklas 					 + adjust)))
1479c074d1c9Sdrahn 		return FALSE;
14802159047fSniklas 
14812159047fSniklas 	      /* We must adjust everything else up a notch.  */
14822159047fSniklas 	      adjust += PCREL16_EXPANSION_ADJUSTMENT;
14832159047fSniklas 
14842159047fSniklas 	      /* mips_relax_pcrel16 handles all the details of this
14852159047fSniklas 		 relocation.  */
14862159047fSniklas 	      continue;
14872159047fSniklas 	    }
14882159047fSniklas 	}
14892159047fSniklas 
14902159047fSniklas       /* If we are relaxing, and this is a reloc against the .text
14912159047fSniklas 	 segment, we may need to adjust it if some branches have been
14922159047fSniklas 	 expanded.  The reloc types which are likely to occur in the
14932159047fSniklas 	 .text section are handled efficiently by mips_relax_section,
14942159047fSniklas 	 and thus do not need to be handled here.  */
14952159047fSniklas       if (ecoff_data (input_bfd)->debug_info.adjust != NULL
14962159047fSniklas 	  && ! int_rel.r_extern
14972159047fSniklas 	  && int_rel.r_symndx == RELOC_SECTION_TEXT
14982159047fSniklas 	  && (strcmp (bfd_get_section_name (input_bfd, input_section),
14992159047fSniklas 		      ".text") != 0
15002159047fSniklas 	      || (int_rel.r_type != MIPS_R_PCREL16
15012159047fSniklas 		  && int_rel.r_type != MIPS_R_SWITCH
15022159047fSniklas 		  && int_rel.r_type != MIPS_R_RELHI
15032159047fSniklas 		  && int_rel.r_type != MIPS_R_RELLO)))
15042159047fSniklas 	{
15052159047fSniklas 	  bfd_vma adr;
15062159047fSniklas 	  struct ecoff_value_adjust *a;
15072159047fSniklas 
15082159047fSniklas 	  /* We need to get the addend so that we know whether we need
15092159047fSniklas 	     to adjust the address.  */
15102159047fSniklas 	  BFD_ASSERT (int_rel.r_type == MIPS_R_REFWORD);
15112159047fSniklas 
15122159047fSniklas 	  adr = bfd_get_32 (input_bfd,
15132159047fSniklas 			    (contents
15142159047fSniklas 			     + adjust
15152159047fSniklas 			     + int_rel.r_vaddr
15162159047fSniklas 			     - input_section->vma));
15172159047fSniklas 
15182159047fSniklas 	  for (a = ecoff_data (input_bfd)->debug_info.adjust;
15192159047fSniklas 	       a != (struct ecoff_value_adjust *) NULL;
15202159047fSniklas 	       a = a->next)
15212159047fSniklas 	    {
15222159047fSniklas 	      if (adr >= a->start && adr < a->end)
15232159047fSniklas 		addend += a->adjust;
15242159047fSniklas 	    }
15252159047fSniklas 	}
15262159047fSniklas 
1527*007c2a45Smiod       if (info->relocatable)
15282159047fSniklas 	{
1529*007c2a45Smiod 	  /* We are generating relocatable output, and must convert
15302159047fSniklas 	     the existing reloc.  */
15312159047fSniklas 	  if (int_rel.r_extern)
15322159047fSniklas 	    {
15332159047fSniklas 	      if ((h->root.type == bfd_link_hash_defined
15342159047fSniklas 		   || h->root.type == bfd_link_hash_defweak)
15352159047fSniklas 		  && ! bfd_is_abs_section (h->root.u.def.section))
15362159047fSniklas 		{
15372159047fSniklas 		  const char *name;
15382159047fSniklas 
15392159047fSniklas 		  /* This symbol is defined in the output.  Convert
15402159047fSniklas 		     the reloc from being against the symbol to being
15412159047fSniklas 		     against the section.  */
15422159047fSniklas 
15432159047fSniklas 		  /* Clear the r_extern bit.  */
15442159047fSniklas 		  int_rel.r_extern = 0;
15452159047fSniklas 
15462159047fSniklas 		  /* Compute a new r_symndx value.  */
15472159047fSniklas 		  s = h->root.u.def.section;
15482159047fSniklas 		  name = bfd_get_section_name (output_bfd,
15492159047fSniklas 					       s->output_section);
15502159047fSniklas 
15512159047fSniklas 		  int_rel.r_symndx = -1;
15522159047fSniklas 		  switch (name[1])
15532159047fSniklas 		    {
15542159047fSniklas 		    case 'b':
15552159047fSniklas 		      if (strcmp (name, ".bss") == 0)
15562159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_BSS;
15572159047fSniklas 		      break;
15582159047fSniklas 		    case 'd':
15592159047fSniklas 		      if (strcmp (name, ".data") == 0)
15602159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_DATA;
15612159047fSniklas 		      break;
15622159047fSniklas 		    case 'f':
15632159047fSniklas 		      if (strcmp (name, ".fini") == 0)
15642159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_FINI;
15652159047fSniklas 		      break;
15662159047fSniklas 		    case 'i':
15672159047fSniklas 		      if (strcmp (name, ".init") == 0)
15682159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_INIT;
15692159047fSniklas 		      break;
15702159047fSniklas 		    case 'l':
15712159047fSniklas 		      if (strcmp (name, ".lit8") == 0)
15722159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_LIT8;
15732159047fSniklas 		      else if (strcmp (name, ".lit4") == 0)
15742159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_LIT4;
15752159047fSniklas 		      break;
15762159047fSniklas 		    case 'r':
15772159047fSniklas 		      if (strcmp (name, ".rdata") == 0)
15782159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_RDATA;
15792159047fSniklas 		      break;
15802159047fSniklas 		    case 's':
15812159047fSniklas 		      if (strcmp (name, ".sdata") == 0)
15822159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_SDATA;
15832159047fSniklas 		      else if (strcmp (name, ".sbss") == 0)
15842159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_SBSS;
15852159047fSniklas 		      break;
15862159047fSniklas 		    case 't':
15872159047fSniklas 		      if (strcmp (name, ".text") == 0)
15882159047fSniklas 			int_rel.r_symndx = RELOC_SECTION_TEXT;
15892159047fSniklas 		      break;
15902159047fSniklas 		    }
15912159047fSniklas 
15922159047fSniklas 		  if (int_rel.r_symndx == -1)
15932159047fSniklas 		    abort ();
15942159047fSniklas 
15952159047fSniklas 		  /* Add the section VMA and the symbol value.  */
15962159047fSniklas 		  relocation = (h->root.u.def.value
15972159047fSniklas 				+ s->output_section->vma
15982159047fSniklas 				+ s->output_offset);
15992159047fSniklas 
16002159047fSniklas 		  /* For a PC relative relocation, the object file
16012159047fSniklas 		     currently holds just the addend.  We must adjust
16022159047fSniklas 		     by the address to get the right value.  */
16032159047fSniklas 		  if (howto->pc_relative)
16042159047fSniklas 		    {
16052159047fSniklas 		      relocation -= int_rel.r_vaddr - input_section->vma;
16062159047fSniklas 
16072159047fSniklas 		      /* If we are converting a RELHI or RELLO reloc
16082159047fSniklas 			 from being against an external symbol to
16092159047fSniklas 			 being against a section, we must put a
16102159047fSniklas 			 special value into the r_offset field.  This
16112159047fSniklas 			 value is the old addend.  The r_offset for
16120c6d0228Sniklas 			 both the RELHI and RELLO relocs are the same,
16130c6d0228Sniklas 			 and we set both when we see RELHI.  */
16142159047fSniklas 		      if (int_rel.r_type == MIPS_R_RELHI)
16152159047fSniklas 			{
16162159047fSniklas 			  long addhi, addlo;
16172159047fSniklas 
16182159047fSniklas 			  addhi = bfd_get_32 (input_bfd,
16192159047fSniklas 					      (contents
16202159047fSniklas 					       + adjust
16212159047fSniklas 					       + int_rel.r_vaddr
16222159047fSniklas 					       - input_section->vma));
16232159047fSniklas 			  addhi &= 0xffff;
16242159047fSniklas 			  if (addhi & 0x8000)
16252159047fSniklas 			    addhi -= 0x10000;
16262159047fSniklas 			  addhi <<= 16;
16272159047fSniklas 
16280c6d0228Sniklas 			  if (! use_lo)
16290c6d0228Sniklas 			    addlo = 0;
16300c6d0228Sniklas 			  else
16310c6d0228Sniklas 			    {
16322159047fSniklas 			      addlo = bfd_get_32 (input_bfd,
16332159047fSniklas 						  (contents
16342159047fSniklas 						   + adjust
16352159047fSniklas 						   + lo_int_rel.r_vaddr
16362159047fSniklas 						   - input_section->vma));
16372159047fSniklas 			      addlo &= 0xffff;
16382159047fSniklas 			      if (addlo & 0x8000)
16392159047fSniklas 				addlo -= 0x10000;
16402159047fSniklas 
16410c6d0228Sniklas 			      lo_int_rel.r_offset = addhi + addlo;
16420c6d0228Sniklas 			    }
16430c6d0228Sniklas 
16442159047fSniklas 			  int_rel.r_offset = addhi + addlo;
16452159047fSniklas 			}
16462159047fSniklas 		    }
16472159047fSniklas 
16482159047fSniklas 		  h = NULL;
16492159047fSniklas 		}
16502159047fSniklas 	      else
16512159047fSniklas 		{
16522159047fSniklas 		  /* Change the symndx value to the right one for the
16532159047fSniklas 		     output BFD.  */
16542159047fSniklas 		  int_rel.r_symndx = h->indx;
16552159047fSniklas 		  if (int_rel.r_symndx == -1)
16562159047fSniklas 		    {
16572159047fSniklas 		      /* This symbol is not being written out.  */
16582159047fSniklas 		      if (! ((*info->callbacks->unattached_reloc)
16592159047fSniklas 			     (info, h->root.root.string, input_bfd,
16602159047fSniklas 			      input_section,
16612159047fSniklas 			      int_rel.r_vaddr - input_section->vma)))
1662c074d1c9Sdrahn 			return FALSE;
16632159047fSniklas 		      int_rel.r_symndx = 0;
16642159047fSniklas 		    }
16652159047fSniklas 		  relocation = 0;
16662159047fSniklas 		}
16672159047fSniklas 	    }
16682159047fSniklas 	  else
16692159047fSniklas 	    {
16702159047fSniklas 	      /* This is a relocation against a section.  Adjust the
16712159047fSniklas 		 value by the amount the section moved.  */
16722159047fSniklas 	      relocation = (s->output_section->vma
16732159047fSniklas 			    + s->output_offset
16742159047fSniklas 			    - s->vma);
16752159047fSniklas 	    }
16762159047fSniklas 
16772159047fSniklas 	  relocation += addend;
16782159047fSniklas 	  addend = 0;
16792159047fSniklas 
16802159047fSniklas 	  /* Adjust a PC relative relocation by removing the reference
16812159047fSniklas 	     to the original address in the section and including the
16822159047fSniklas 	     reference to the new address.  However, external RELHI
16832159047fSniklas 	     and RELLO relocs are PC relative, but don't include any
16842159047fSniklas 	     reference to the address.  The addend is merely an
16852159047fSniklas 	     addend.  */
16862159047fSniklas 	  if (howto->pc_relative
16872159047fSniklas 	      && (! int_rel.r_extern
16882159047fSniklas 		  || (int_rel.r_type != MIPS_R_RELHI
16892159047fSniklas 		      && int_rel.r_type != MIPS_R_RELLO)))
16902159047fSniklas 	    relocation -= (input_section->output_section->vma
16912159047fSniklas 			   + input_section->output_offset
16922159047fSniklas 			   - input_section->vma);
16932159047fSniklas 
16942159047fSniklas 	  /* Adjust the contents.  */
16952159047fSniklas 	  if (relocation == 0)
16962159047fSniklas 	    r = bfd_reloc_ok;
16972159047fSniklas 	  else
16982159047fSniklas 	    {
16992159047fSniklas 	      if (int_rel.r_type != MIPS_R_REFHI
17002159047fSniklas 		  && int_rel.r_type != MIPS_R_RELHI)
17012159047fSniklas 		r = _bfd_relocate_contents (howto, input_bfd, relocation,
17022159047fSniklas 					    (contents
17032159047fSniklas 					     + adjust
17042159047fSniklas 					     + int_rel.r_vaddr
17052159047fSniklas 					     - input_section->vma));
17062159047fSniklas 	      else
17072159047fSniklas 		{
17080c6d0228Sniklas 		  mips_relocate_hi (&int_rel,
17090c6d0228Sniklas 				    use_lo ? &lo_int_rel : NULL,
17102159047fSniklas 				    input_bfd, input_section, contents,
17112159047fSniklas 				    adjust, relocation,
17122159047fSniklas 				    int_rel.r_type == MIPS_R_RELHI);
17132159047fSniklas 		  r = bfd_reloc_ok;
17142159047fSniklas 		}
17152159047fSniklas 	    }
17162159047fSniklas 
17172159047fSniklas 	  /* Adjust the reloc address.  */
17182159047fSniklas 	  int_rel.r_vaddr += (input_section->output_section->vma
17192159047fSniklas 			      + input_section->output_offset
17202159047fSniklas 			      - input_section->vma);
17212159047fSniklas 
17222159047fSniklas 	  /* Save the changed reloc information.  */
17232159047fSniklas 	  mips_ecoff_swap_reloc_out (input_bfd, &int_rel, (PTR) ext_rel);
17242159047fSniklas 	}
17252159047fSniklas       else
17262159047fSniklas 	{
17272159047fSniklas 	  /* We are producing a final executable.  */
17282159047fSniklas 	  if (int_rel.r_extern)
17292159047fSniklas 	    {
17302159047fSniklas 	      /* This is a reloc against a symbol.  */
17312159047fSniklas 	      if (h->root.type == bfd_link_hash_defined
17322159047fSniklas 		  || h->root.type == bfd_link_hash_defweak)
17332159047fSniklas 		{
17342159047fSniklas 		  asection *hsec;
17352159047fSniklas 
17362159047fSniklas 		  hsec = h->root.u.def.section;
17372159047fSniklas 		  relocation = (h->root.u.def.value
17382159047fSniklas 				+ hsec->output_section->vma
17392159047fSniklas 				+ hsec->output_offset);
17402159047fSniklas 		}
17412159047fSniklas 	      else
17422159047fSniklas 		{
17432159047fSniklas 		  if (! ((*info->callbacks->undefined_symbol)
17442159047fSniklas 			 (info, h->root.root.string, input_bfd,
17452159047fSniklas 			  input_section,
1746c074d1c9Sdrahn 			  int_rel.r_vaddr - input_section->vma, TRUE)))
1747c074d1c9Sdrahn 		    return FALSE;
17482159047fSniklas 		  relocation = 0;
17492159047fSniklas 		}
17502159047fSniklas 	    }
17512159047fSniklas 	  else
17522159047fSniklas 	    {
17532159047fSniklas 	      /* This is a reloc against a section.  */
17542159047fSniklas 	      relocation = (s->output_section->vma
17552159047fSniklas 			    + s->output_offset
17562159047fSniklas 			    - s->vma);
17572159047fSniklas 
17582159047fSniklas 	      /* A PC relative reloc is already correct in the object
17592159047fSniklas 		 file.  Make it look like a pcrel_offset relocation by
17602159047fSniklas 		 adding in the start address.  */
17612159047fSniklas 	      if (howto->pc_relative)
17622159047fSniklas 		{
17630c6d0228Sniklas 		  if (int_rel.r_type != MIPS_R_RELHI || ! use_lo)
17642159047fSniklas 		    relocation += int_rel.r_vaddr + adjust;
17652159047fSniklas 		  else
17662159047fSniklas 		    relocation += lo_int_rel.r_vaddr + adjust;
17672159047fSniklas 		}
17682159047fSniklas 	    }
17692159047fSniklas 
17702159047fSniklas 	  if (int_rel.r_type != MIPS_R_REFHI
17712159047fSniklas 	      && int_rel.r_type != MIPS_R_RELHI)
17722159047fSniklas 	    r = _bfd_final_link_relocate (howto,
17732159047fSniklas 					  input_bfd,
17742159047fSniklas 					  input_section,
17752159047fSniklas 					  contents,
17762159047fSniklas 					  (int_rel.r_vaddr
17772159047fSniklas 					   - input_section->vma
17782159047fSniklas 					   + adjust),
17792159047fSniklas 					  relocation,
17802159047fSniklas 					  addend);
17812159047fSniklas 	  else
17822159047fSniklas 	    {
17830c6d0228Sniklas 	      mips_relocate_hi (&int_rel,
17840c6d0228Sniklas 				use_lo ? &lo_int_rel : NULL,
17850c6d0228Sniklas 				input_bfd, input_section, contents, adjust,
17862159047fSniklas 				relocation,
17872159047fSniklas 				int_rel.r_type == MIPS_R_RELHI);
17882159047fSniklas 	      r = bfd_reloc_ok;
17892159047fSniklas 	    }
17902159047fSniklas 	}
17912159047fSniklas 
17922159047fSniklas       /* MIPS_R_JMPADDR requires peculiar overflow detection.  The
17932159047fSniklas 	 instruction provides a 28 bit address (the two lower bits are
17942159047fSniklas 	 implicit zeroes) which is combined with the upper four bits
17952159047fSniklas 	 of the instruction address.  */
17962159047fSniklas       if (r == bfd_reloc_ok
17972159047fSniklas 	  && int_rel.r_type == MIPS_R_JMPADDR
17982159047fSniklas 	  && (((relocation
17992159047fSniklas 		+ addend
18002159047fSniklas 		+ (int_rel.r_extern ? 0 : s->vma))
18012159047fSniklas 	       & 0xf0000000)
18022159047fSniklas 	      != ((input_section->output_section->vma
18032159047fSniklas 		   + input_section->output_offset
18042159047fSniklas 		   + (int_rel.r_vaddr - input_section->vma)
18052159047fSniklas 		   + adjust)
18062159047fSniklas 		  & 0xf0000000)))
18072159047fSniklas 	r = bfd_reloc_overflow;
18082159047fSniklas 
18092159047fSniklas       if (r != bfd_reloc_ok)
18102159047fSniklas 	{
18112159047fSniklas 	  switch (r)
18122159047fSniklas 	    {
18132159047fSniklas 	    default:
18142159047fSniklas 	    case bfd_reloc_outofrange:
18152159047fSniklas 	      abort ();
18162159047fSniklas 	    case bfd_reloc_overflow:
18172159047fSniklas 	      {
18182159047fSniklas 		const char *name;
18192159047fSniklas 
18202159047fSniklas 		if (int_rel.r_extern)
18212159047fSniklas 		  name = h->root.root.string;
18222159047fSniklas 		else
18232159047fSniklas 		  name = bfd_section_name (input_bfd, s);
18242159047fSniklas 		if (! ((*info->callbacks->reloc_overflow)
18252159047fSniklas 		       (info, name, howto->name, (bfd_vma) 0,
18262159047fSniklas 			input_bfd, input_section,
18272159047fSniklas 			int_rel.r_vaddr - input_section->vma)))
1828c074d1c9Sdrahn 		  return FALSE;
18292159047fSniklas 	      }
18302159047fSniklas 	      break;
18312159047fSniklas 	    }
18322159047fSniklas 	}
18332159047fSniklas     }
18342159047fSniklas 
1835c074d1c9Sdrahn   return TRUE;
18362159047fSniklas }
18372159047fSniklas 
18382159047fSniklas /* Read in the relocs for a section.  */
18392159047fSniklas 
1840c074d1c9Sdrahn static bfd_boolean
mips_read_relocs(abfd,sec)18412159047fSniklas mips_read_relocs (abfd, sec)
18422159047fSniklas      bfd *abfd;
18432159047fSniklas      asection *sec;
18442159047fSniklas {
18452159047fSniklas   struct ecoff_section_tdata *section_tdata;
1846c074d1c9Sdrahn   bfd_size_type amt;
18472159047fSniklas 
18482159047fSniklas   section_tdata = ecoff_section_data (abfd, sec);
18492159047fSniklas   if (section_tdata == (struct ecoff_section_tdata *) NULL)
18502159047fSniklas     {
1851c074d1c9Sdrahn       amt = sizeof (struct ecoff_section_tdata);
1852c074d1c9Sdrahn       sec->used_by_bfd = (PTR) bfd_alloc (abfd, amt);
18532159047fSniklas       if (sec->used_by_bfd == NULL)
1854c074d1c9Sdrahn 	return FALSE;
18552159047fSniklas 
18562159047fSniklas       section_tdata = ecoff_section_data (abfd, sec);
18572159047fSniklas       section_tdata->external_relocs = NULL;
18582159047fSniklas       section_tdata->contents = NULL;
18592159047fSniklas       section_tdata->offsets = NULL;
18602159047fSniklas     }
18612159047fSniklas 
18622159047fSniklas   if (section_tdata->external_relocs == NULL)
18632159047fSniklas     {
1864c074d1c9Sdrahn       amt = ecoff_backend (abfd)->external_reloc_size;
1865c074d1c9Sdrahn       amt *= sec->reloc_count;
1866c074d1c9Sdrahn       section_tdata->external_relocs = (PTR) bfd_alloc (abfd, amt);
1867c074d1c9Sdrahn       if (section_tdata->external_relocs == NULL && amt != 0)
1868c074d1c9Sdrahn 	return FALSE;
18692159047fSniklas 
18702159047fSniklas       if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
1871c074d1c9Sdrahn 	  || bfd_bread (section_tdata->external_relocs, amt, abfd) != amt)
1872c074d1c9Sdrahn 	return FALSE;
18732159047fSniklas     }
18742159047fSniklas 
1875c074d1c9Sdrahn   return TRUE;
18762159047fSniklas }
18772159047fSniklas 
18782159047fSniklas /* Relax a section when linking a MIPS ECOFF file.  This is used for
18792159047fSniklas    embedded PIC code, which always uses PC relative branches which
18802159047fSniklas    only have an 18 bit range on MIPS.  If a branch is not in range, we
18812159047fSniklas    generate a long instruction sequence to compensate.  Each time we
18822159047fSniklas    find a branch to expand, we have to check all the others again to
18832159047fSniklas    make sure they are still in range.  This is slow, but it only has
18842159047fSniklas    to be done when -relax is passed to the linker.
18852159047fSniklas 
18862159047fSniklas    This routine figures out which branches need to expand; the actual
18872159047fSniklas    expansion is done in mips_relocate_section when the section
18882159047fSniklas    contents are relocated.  The information is stored in the offsets
18892159047fSniklas    field of the ecoff_section_tdata structure.  An offset of 1 means
18902159047fSniklas    that the branch must be expanded into a multi-instruction PC
18912159047fSniklas    relative branch (such an offset will only occur for a PC relative
18922159047fSniklas    branch to an external symbol).  Any other offset must be a multiple
18932159047fSniklas    of four, and is the amount to change the branch by (such an offset
18942159047fSniklas    will only occur for a PC relative branch within the same section).
18952159047fSniklas 
18962159047fSniklas    We do not modify the section relocs or contents themselves so that
18972159047fSniklas    if memory usage becomes an issue we can discard them and read them
18982159047fSniklas    again.  The only information we must save in memory between this
18992159047fSniklas    routine and the mips_relocate_section routine is the table of
19002159047fSniklas    offsets.  */
19012159047fSniklas 
1902c074d1c9Sdrahn static bfd_boolean
mips_relax_section(abfd,sec,info,again)19032159047fSniklas mips_relax_section (abfd, sec, info, again)
19042159047fSniklas      bfd *abfd;
19052159047fSniklas      asection *sec;
19062159047fSniklas      struct bfd_link_info *info;
1907c074d1c9Sdrahn      bfd_boolean *again;
19082159047fSniklas {
19092159047fSniklas   struct ecoff_section_tdata *section_tdata;
19102159047fSniklas   bfd_byte *contents = NULL;
19112159047fSniklas   long *offsets;
19122159047fSniklas   struct external_reloc *ext_rel;
19132159047fSniklas   struct external_reloc *ext_rel_end;
19142159047fSniklas   unsigned int i;
19152159047fSniklas 
19162159047fSniklas   /* Assume we are not going to need another pass.  */
1917c074d1c9Sdrahn   *again = FALSE;
19182159047fSniklas 
19192159047fSniklas   /* If we are not generating an ECOFF file, this is much too
19202159047fSniklas      confusing to deal with.  */
19212159047fSniklas   if (info->hash->creator->flavour != bfd_get_flavour (abfd))
1922c074d1c9Sdrahn     return TRUE;
19232159047fSniklas 
19242159047fSniklas   /* If there are no relocs, there is nothing to do.  */
19252159047fSniklas   if (sec->reloc_count == 0)
1926c074d1c9Sdrahn     return TRUE;
19272159047fSniklas 
19282159047fSniklas   /* We are only interested in PC relative relocs, and why would there
19292159047fSniklas      ever be one from anything but the .text section?  */
19302159047fSniklas   if (strcmp (bfd_get_section_name (abfd, sec), ".text") != 0)
1931c074d1c9Sdrahn     return TRUE;
19322159047fSniklas 
19332159047fSniklas   /* Read in the relocs, if we haven't already got them.  */
19342159047fSniklas   section_tdata = ecoff_section_data (abfd, sec);
19352159047fSniklas   if (section_tdata == (struct ecoff_section_tdata *) NULL
19362159047fSniklas       || section_tdata->external_relocs == NULL)
19372159047fSniklas     {
19382159047fSniklas       if (! mips_read_relocs (abfd, sec))
19392159047fSniklas 	goto error_return;
19402159047fSniklas       section_tdata = ecoff_section_data (abfd, sec);
19412159047fSniklas     }
19422159047fSniklas 
19432159047fSniklas   if (sec->_cooked_size == 0)
19442159047fSniklas     {
19452159047fSniklas       /* We must initialize _cooked_size only the first time we are
19462159047fSniklas 	 called.  */
19472159047fSniklas       sec->_cooked_size = sec->_raw_size;
19482159047fSniklas     }
19492159047fSniklas 
19502159047fSniklas   contents = section_tdata->contents;
19512159047fSniklas   offsets = section_tdata->offsets;
19522159047fSniklas 
19532159047fSniklas   /* Look for any external PC relative relocs.  Internal PC relative
19542159047fSniklas      relocs are already correct in the object file, so they certainly
19552159047fSniklas      can not overflow.  */
19562159047fSniklas   ext_rel = (struct external_reloc *) section_tdata->external_relocs;
19572159047fSniklas   ext_rel_end = ext_rel + sec->reloc_count;
19582159047fSniklas   for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
19592159047fSniklas     {
19602159047fSniklas       struct internal_reloc int_rel;
19612159047fSniklas       struct ecoff_link_hash_entry *h;
19622159047fSniklas       asection *hsec;
19632159047fSniklas       bfd_signed_vma relocation;
19642159047fSniklas       struct external_reloc *adj_ext_rel;
19652159047fSniklas       unsigned int adj_i;
19662159047fSniklas       unsigned long ext_count;
19672159047fSniklas       struct ecoff_link_hash_entry **adj_h_ptr;
19682159047fSniklas       struct ecoff_link_hash_entry **adj_h_ptr_end;
19692159047fSniklas       struct ecoff_value_adjust *adjust;
1970c074d1c9Sdrahn       bfd_size_type amt;
19712159047fSniklas 
19722159047fSniklas       /* If we have already expanded this reloc, we certainly don't
19732159047fSniklas 	 need to do it again.  */
19742159047fSniklas       if (offsets != (long *) NULL && offsets[i] == 1)
19752159047fSniklas 	continue;
19762159047fSniklas 
19772159047fSniklas       /* Quickly check that this reloc is external PCREL16.  */
1978c88b1d6cSniklas       if (bfd_header_big_endian (abfd))
19792159047fSniklas 	{
19802159047fSniklas 	  if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_BIG) == 0
19812159047fSniklas 	      || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_BIG)
19822159047fSniklas 		   >> RELOC_BITS3_TYPE_SH_BIG)
19832159047fSniklas 		  != MIPS_R_PCREL16))
19842159047fSniklas 	    continue;
19852159047fSniklas 	}
19862159047fSniklas       else
19872159047fSniklas 	{
19882159047fSniklas 	  if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) == 0
19892159047fSniklas 	      || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
19902159047fSniklas 		   >> RELOC_BITS3_TYPE_SH_LITTLE)
19912159047fSniklas 		  != MIPS_R_PCREL16))
19922159047fSniklas 	    continue;
19932159047fSniklas 	}
19942159047fSniklas 
19952159047fSniklas       mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel);
19962159047fSniklas 
19972159047fSniklas       h = ecoff_data (abfd)->sym_hashes[int_rel.r_symndx];
19982159047fSniklas       if (h == (struct ecoff_link_hash_entry *) NULL)
19992159047fSniklas 	abort ();
20002159047fSniklas 
20012159047fSniklas       if (h->root.type != bfd_link_hash_defined
20022159047fSniklas 	  && h->root.type != bfd_link_hash_defweak)
20032159047fSniklas 	{
20042159047fSniklas 	  /* Just ignore undefined symbols.  These will presumably
20052159047fSniklas 	     generate an error later in the link.  */
20062159047fSniklas 	  continue;
20072159047fSniklas 	}
20082159047fSniklas 
20092159047fSniklas       /* Get the value of the symbol.  */
20102159047fSniklas       hsec = h->root.u.def.section;
20112159047fSniklas       relocation = (h->root.u.def.value
20122159047fSniklas 		    + hsec->output_section->vma
20132159047fSniklas 		    + hsec->output_offset);
20142159047fSniklas 
20152159047fSniklas       /* Subtract out the current address.  */
20162159047fSniklas       relocation -= (sec->output_section->vma
20172159047fSniklas 		     + sec->output_offset
20182159047fSniklas 		     + (int_rel.r_vaddr - sec->vma));
20192159047fSniklas 
20202159047fSniklas       /* The addend is stored in the object file.  In the normal case
20212159047fSniklas 	 of ``bal symbol'', the addend will be -4.  It will only be
20222159047fSniklas 	 different in the case of ``bal symbol+constant''.  To avoid
20232159047fSniklas 	 always reading in the section contents, we don't check the
20242159047fSniklas 	 addend in the object file (we could easily check the contents
20252159047fSniklas 	 if we happen to have already read them in, but I fear that
20262159047fSniklas 	 this could be confusing).  This means we will screw up if
20272159047fSniklas 	 there is a branch to a symbol that is in range, but added to
20282159047fSniklas 	 a constant which puts it out of range; in such a case the
20292159047fSniklas 	 link will fail with a reloc overflow error.  Since the
20302159047fSniklas 	 compiler will never generate such code, it should be easy
20312159047fSniklas 	 enough to work around it by changing the assembly code in the
20322159047fSniklas 	 source file.  */
20332159047fSniklas       relocation -= 4;
20342159047fSniklas 
20352159047fSniklas       /* Now RELOCATION is the number we want to put in the object
20362159047fSniklas 	 file.  See whether it fits.  */
20372159047fSniklas       if (relocation >= -0x20000 && relocation < 0x20000)
20382159047fSniklas 	continue;
20392159047fSniklas 
20402159047fSniklas       /* Now that we know this reloc needs work, which will rarely
20412159047fSniklas 	 happen, go ahead and grab the section contents.  */
20422159047fSniklas       if (contents == (bfd_byte *) NULL)
20432159047fSniklas 	{
20442159047fSniklas 	  if (info->keep_memory)
20452159047fSniklas 	    contents = (bfd_byte *) bfd_alloc (abfd, sec->_raw_size);
20462159047fSniklas 	  else
2047c074d1c9Sdrahn 	    contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
20482159047fSniklas 	  if (contents == (bfd_byte *) NULL)
20492159047fSniklas 	    goto error_return;
20502159047fSniklas 	  if (! bfd_get_section_contents (abfd, sec, (PTR) contents,
20512159047fSniklas 					  (file_ptr) 0, sec->_raw_size))
20522159047fSniklas 	    goto error_return;
20532159047fSniklas 	  if (info->keep_memory)
20542159047fSniklas 	    section_tdata->contents = contents;
20552159047fSniklas 	}
20562159047fSniklas 
20572159047fSniklas       /* We only support changing the bal instruction.  It would be
20582159047fSniklas 	 possible to handle other PC relative branches, but some of
20592159047fSniklas 	 them (the conditional branches) would require a different
20602159047fSniklas 	 length instruction sequence which would complicate both this
20612159047fSniklas 	 routine and mips_relax_pcrel16.  It could be written if
20622159047fSniklas 	 somebody felt it were important.  Ignoring this reloc will
20632159047fSniklas 	 presumably cause a reloc overflow error later on.  */
20642159047fSniklas       if (bfd_get_32 (abfd, contents + int_rel.r_vaddr - sec->vma)
20652159047fSniklas 	  != 0x0411ffff) /* bgezal $0,. == bal .  */
20662159047fSniklas 	continue;
20672159047fSniklas 
20682159047fSniklas       /* Bother.  We need to expand this reloc, and we will need to
20692159047fSniklas 	 make another relaxation pass since this change may put other
20702159047fSniklas 	 relocs out of range.  We need to examine the local branches
20712159047fSniklas 	 and we need to allocate memory to hold the offsets we must
20722159047fSniklas 	 add to them.  We also need to adjust the values of all
20732159047fSniklas 	 symbols in the object file following this location.  */
20742159047fSniklas 
20752159047fSniklas       sec->_cooked_size += PCREL16_EXPANSION_ADJUSTMENT;
2076c074d1c9Sdrahn       *again = TRUE;
20772159047fSniklas 
20782159047fSniklas       if (offsets == (long *) NULL)
20792159047fSniklas 	{
2080c074d1c9Sdrahn 	  bfd_size_type size;
20812159047fSniklas 
2082c074d1c9Sdrahn 	  size = (bfd_size_type) sec->reloc_count * sizeof (long);
2083c074d1c9Sdrahn 	  offsets = (long *) bfd_zalloc (abfd, size);
20842159047fSniklas 	  if (offsets == (long *) NULL)
20852159047fSniklas 	    goto error_return;
20862159047fSniklas 	  section_tdata->offsets = offsets;
20872159047fSniklas 	}
20882159047fSniklas 
20892159047fSniklas       offsets[i] = 1;
20902159047fSniklas 
20912159047fSniklas       /* Now look for all PC relative references that cross this reloc
20922159047fSniklas 	 and adjust their offsets.  */
20932159047fSniklas       adj_ext_rel = (struct external_reloc *) section_tdata->external_relocs;
20942159047fSniklas       for (adj_i = 0; adj_ext_rel < ext_rel_end; adj_ext_rel++, adj_i++)
20952159047fSniklas 	{
20962159047fSniklas 	  struct internal_reloc adj_int_rel;
20972159047fSniklas 	  bfd_vma start, stop;
20982159047fSniklas 	  int change;
20992159047fSniklas 
21002159047fSniklas 	  mips_ecoff_swap_reloc_in (abfd, (PTR) adj_ext_rel, &adj_int_rel);
21012159047fSniklas 
21022159047fSniklas 	  if (adj_int_rel.r_type == MIPS_R_PCREL16)
21032159047fSniklas 	    {
21042159047fSniklas 	      unsigned long insn;
21052159047fSniklas 
21062159047fSniklas 	      /* We only care about local references.  External ones
21072159047fSniklas 		 will be relocated correctly anyhow.  */
21082159047fSniklas 	      if (adj_int_rel.r_extern)
21092159047fSniklas 		continue;
21102159047fSniklas 
21112159047fSniklas 	      /* We are only interested in a PC relative reloc within
21122159047fSniklas 		 this section.  FIXME: Cross section PC relative
21132159047fSniklas 		 relocs may not be handled correctly; does anybody
21142159047fSniklas 		 care?  */
21152159047fSniklas 	      if (adj_int_rel.r_symndx != RELOC_SECTION_TEXT)
21162159047fSniklas 		continue;
21172159047fSniklas 
21182159047fSniklas 	      start = adj_int_rel.r_vaddr;
21192159047fSniklas 
21202159047fSniklas 	      insn = bfd_get_32 (abfd,
21212159047fSniklas 				 contents + adj_int_rel.r_vaddr - sec->vma);
21222159047fSniklas 
21232159047fSniklas 	      stop = (insn & 0xffff) << 2;
21242159047fSniklas 	      if ((stop & 0x20000) != 0)
21252159047fSniklas 		stop -= 0x40000;
21262159047fSniklas 	      stop += adj_int_rel.r_vaddr + 4;
21272159047fSniklas 	    }
21282159047fSniklas 	  else if (adj_int_rel.r_type == MIPS_R_RELHI)
21292159047fSniklas 	    {
21302159047fSniklas 	      struct internal_reloc rello;
21312159047fSniklas 	      long addhi, addlo;
21322159047fSniklas 
21332159047fSniklas 	      /* The next reloc must be MIPS_R_RELLO, and we handle
21342159047fSniklas 		 them together.  */
21352159047fSniklas 	      BFD_ASSERT (adj_ext_rel + 1 < ext_rel_end);
21362159047fSniklas 
21372159047fSniklas 	      mips_ecoff_swap_reloc_in (abfd, (PTR) (adj_ext_rel + 1), &rello);
21382159047fSniklas 
21392159047fSniklas 	      BFD_ASSERT (rello.r_type == MIPS_R_RELLO);
21402159047fSniklas 
21412159047fSniklas 	      addhi = bfd_get_32 (abfd,
21422159047fSniklas 				   contents + adj_int_rel.r_vaddr - sec->vma);
21432159047fSniklas 	      addhi &= 0xffff;
21442159047fSniklas 	      if (addhi & 0x8000)
21452159047fSniklas 		addhi -= 0x10000;
21462159047fSniklas 	      addhi <<= 16;
21472159047fSniklas 
21482159047fSniklas 	      addlo = bfd_get_32 (abfd, contents + rello.r_vaddr - sec->vma);
21492159047fSniklas 	      addlo &= 0xffff;
21502159047fSniklas 	      if (addlo & 0x8000)
21512159047fSniklas 		addlo -= 0x10000;
21522159047fSniklas 
21532159047fSniklas 	      if (adj_int_rel.r_extern)
21542159047fSniklas 		{
21552159047fSniklas 		  /* The value we want here is
21562159047fSniklas 		       sym - RELLOaddr + addend
21572159047fSniklas 		     which we can express as
21582159047fSniklas 		       sym - (RELLOaddr - addend)
21592159047fSniklas 		     Therefore if we are expanding the area between
21602159047fSniklas 		     RELLOaddr and RELLOaddr - addend we must adjust
21612159047fSniklas 		     the addend.  This is admittedly ambiguous, since
21622159047fSniklas 		     we might mean (sym + addend) - RELLOaddr, but in
21632159047fSniklas 		     practice we don't, and there is no way to handle
21642159047fSniklas 		     that case correctly since at this point we have
21652159047fSniklas 		     no idea whether any reloc is being expanded
21662159047fSniklas 		     between sym and sym + addend.  */
21672159047fSniklas 		  start = rello.r_vaddr - (addhi + addlo);
21682159047fSniklas 		  stop = rello.r_vaddr;
21692159047fSniklas 		}
21702159047fSniklas 	      else
21712159047fSniklas 		{
21722159047fSniklas 		  /* An internal RELHI/RELLO pair represents the
21732159047fSniklas 		     difference between two addresses, $LC0 - foo.
21742159047fSniklas 		     The symndx value is actually the difference
21752159047fSniklas 		     between the reloc address and $LC0.  This lets us
21762159047fSniklas 		     compute $LC0, and, by considering the addend,
21772159047fSniklas 		     foo.  If the reloc we are expanding falls between
21782159047fSniklas 		     those two relocs, we must adjust the addend.  At
21792159047fSniklas 		     this point, the symndx value is actually in the
21802159047fSniklas 		     r_offset field, where it was put by
21812159047fSniklas 		     mips_ecoff_swap_reloc_in.  */
21822159047fSniklas 		  start = rello.r_vaddr - adj_int_rel.r_offset;
21832159047fSniklas 		  stop = start + addhi + addlo;
21842159047fSniklas 		}
21852159047fSniklas 	    }
21862159047fSniklas 	  else if (adj_int_rel.r_type == MIPS_R_SWITCH)
21872159047fSniklas 	    {
21882159047fSniklas 	      /* A MIPS_R_SWITCH reloc represents a word of the form
21892159047fSniklas 		   .word $L3-$LS12
21902159047fSniklas 		 The value in the object file is correct, assuming the
21912159047fSniklas 		 original value of $L3.  The symndx value is actually
21922159047fSniklas 		 the difference between the reloc address and $LS12.
21932159047fSniklas 		 This lets us compute the original value of $LS12 as
21942159047fSniklas 		   vaddr - symndx
21952159047fSniklas 		 and the original value of $L3 as
21962159047fSniklas 		   vaddr - symndx + addend
21972159047fSniklas 		 where addend is the value from the object file.  At
21982159047fSniklas 		 this point, the symndx value is actually found in the
21992159047fSniklas 		 r_offset field, since it was moved by
22002159047fSniklas 		 mips_ecoff_swap_reloc_in.  */
22012159047fSniklas 	      start = adj_int_rel.r_vaddr - adj_int_rel.r_offset;
22022159047fSniklas 	      stop = start + bfd_get_32 (abfd,
22032159047fSniklas 					 (contents
22042159047fSniklas 					  + adj_int_rel.r_vaddr
22052159047fSniklas 					  - sec->vma));
22062159047fSniklas 	    }
22072159047fSniklas 	  else
22082159047fSniklas 	    continue;
22092159047fSniklas 
22102159047fSniklas 	  /* If the range expressed by this reloc, which is the
22112159047fSniklas 	     distance between START and STOP crosses the reloc we are
22122159047fSniklas 	     expanding, we must adjust the offset.  The sign of the
22132159047fSniklas 	     adjustment depends upon the direction in which the range
22142159047fSniklas 	     crosses the reloc being expanded.  */
22152159047fSniklas 	  if (start <= int_rel.r_vaddr && stop > int_rel.r_vaddr)
22162159047fSniklas 	    change = PCREL16_EXPANSION_ADJUSTMENT;
22172159047fSniklas 	  else if (start > int_rel.r_vaddr && stop <= int_rel.r_vaddr)
22182159047fSniklas 	    change = - PCREL16_EXPANSION_ADJUSTMENT;
22192159047fSniklas 	  else
22202159047fSniklas 	    change = 0;
22212159047fSniklas 
22222159047fSniklas 	  offsets[adj_i] += change;
22232159047fSniklas 
22242159047fSniklas 	  if (adj_int_rel.r_type == MIPS_R_RELHI)
22252159047fSniklas 	    {
22262159047fSniklas 	      adj_ext_rel++;
22272159047fSniklas 	      adj_i++;
22282159047fSniklas 	      offsets[adj_i] += change;
22292159047fSniklas 	    }
22302159047fSniklas 	}
22312159047fSniklas 
22322159047fSniklas       /* Find all symbols in this section defined by this object file
22332159047fSniklas 	 and adjust their values.  Note that we decide whether to
22342159047fSniklas 	 adjust the value based on the value stored in the ECOFF EXTR
22352159047fSniklas 	 structure, because the value stored in the hash table may
22362159047fSniklas 	 have been changed by an earlier expanded reloc and thus may
22372159047fSniklas 	 no longer correctly indicate whether the symbol is before or
22382159047fSniklas 	 after the expanded reloc.  */
22392159047fSniklas       ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
22402159047fSniklas       adj_h_ptr = ecoff_data (abfd)->sym_hashes;
22412159047fSniklas       adj_h_ptr_end = adj_h_ptr + ext_count;
22422159047fSniklas       for (; adj_h_ptr < adj_h_ptr_end; adj_h_ptr++)
22432159047fSniklas 	{
22442159047fSniklas 	  struct ecoff_link_hash_entry *adj_h;
22452159047fSniklas 
22462159047fSniklas 	  adj_h = *adj_h_ptr;
22472159047fSniklas 	  if (adj_h != (struct ecoff_link_hash_entry *) NULL
22482159047fSniklas 	      && (adj_h->root.type == bfd_link_hash_defined
22492159047fSniklas 		  || adj_h->root.type == bfd_link_hash_defweak)
22502159047fSniklas 	      && adj_h->root.u.def.section == sec
22512159047fSniklas 	      && adj_h->esym.asym.value > int_rel.r_vaddr)
22522159047fSniklas 	    adj_h->root.u.def.value += PCREL16_EXPANSION_ADJUSTMENT;
22532159047fSniklas 	}
22542159047fSniklas 
22552159047fSniklas       /* Add an entry to the symbol value adjust list.  This is used
22562159047fSniklas 	 by bfd_ecoff_debug_accumulate to adjust the values of
22572159047fSniklas 	 internal symbols and FDR's.  */
2258c074d1c9Sdrahn       amt = sizeof (struct ecoff_value_adjust);
2259c074d1c9Sdrahn       adjust = (struct ecoff_value_adjust *) bfd_alloc (abfd, amt);
22602159047fSniklas       if (adjust == (struct ecoff_value_adjust *) NULL)
22612159047fSniklas 	goto error_return;
22622159047fSniklas 
22632159047fSniklas       adjust->start = int_rel.r_vaddr;
22642159047fSniklas       adjust->end = sec->vma + sec->_raw_size;
22652159047fSniklas       adjust->adjust = PCREL16_EXPANSION_ADJUSTMENT;
22662159047fSniklas 
22672159047fSniklas       adjust->next = ecoff_data (abfd)->debug_info.adjust;
22682159047fSniklas       ecoff_data (abfd)->debug_info.adjust = adjust;
22692159047fSniklas     }
22702159047fSniklas 
22712159047fSniklas   if (contents != (bfd_byte *) NULL && ! info->keep_memory)
22722159047fSniklas     free (contents);
22732159047fSniklas 
2274c074d1c9Sdrahn   return TRUE;
22752159047fSniklas 
22762159047fSniklas  error_return:
22772159047fSniklas   if (contents != (bfd_byte *) NULL && ! info->keep_memory)
22782159047fSniklas     free (contents);
2279c074d1c9Sdrahn   return FALSE;
22802159047fSniklas }
22812159047fSniklas 
22822159047fSniklas /* This routine is called from mips_relocate_section when a PC
22832159047fSniklas    relative reloc must be expanded into the five instruction sequence.
22842159047fSniklas    It handles all the details of the expansion, including resolving
22852159047fSniklas    the reloc.  */
22862159047fSniklas 
2287c074d1c9Sdrahn static bfd_boolean
mips_relax_pcrel16(info,input_bfd,input_section,h,location,address)22882159047fSniklas mips_relax_pcrel16 (info, input_bfd, input_section, h, location, address)
2289b305b0f1Sespie      struct bfd_link_info *info ATTRIBUTE_UNUSED;
22902159047fSniklas      bfd *input_bfd;
2291b305b0f1Sespie      asection *input_section ATTRIBUTE_UNUSED;
22922159047fSniklas      struct ecoff_link_hash_entry *h;
22932159047fSniklas      bfd_byte *location;
22942159047fSniklas      bfd_vma address;
22952159047fSniklas {
22962159047fSniklas   bfd_vma relocation;
22972159047fSniklas 
22982159047fSniklas   /* 0x0411ffff is bgezal $0,. == bal .  */
22992159047fSniklas   BFD_ASSERT (bfd_get_32 (input_bfd, location) == 0x0411ffff);
23002159047fSniklas 
23012159047fSniklas   /* We need to compute the distance between the symbol and the
23022159047fSniklas      current address plus eight.  */
23032159047fSniklas   relocation = (h->root.u.def.value
23042159047fSniklas 		+ h->root.u.def.section->output_section->vma
23052159047fSniklas 		+ h->root.u.def.section->output_offset);
23062159047fSniklas   relocation -= address + 8;
23072159047fSniklas 
23082159047fSniklas   /* If the lower half is negative, increment the upper 16 half.  */
23092159047fSniklas   if ((relocation & 0x8000) != 0)
23102159047fSniklas     relocation += 0x10000;
23112159047fSniklas 
2312c074d1c9Sdrahn   bfd_put_32 (input_bfd, (bfd_vma) 0x04110001, location); /* bal .+8 */
23132159047fSniklas   bfd_put_32 (input_bfd,
23142159047fSniklas 	      0x3c010000 | ((relocation >> 16) & 0xffff), /* lui $at,XX */
23152159047fSniklas 	      location + 4);
23162159047fSniklas   bfd_put_32 (input_bfd,
23172159047fSniklas 	      0x24210000 | (relocation & 0xffff), /* addiu $at,$at,XX */
23182159047fSniklas 	      location + 8);
2319c074d1c9Sdrahn   bfd_put_32 (input_bfd,
2320c074d1c9Sdrahn 	      (bfd_vma) 0x003f0821, location + 12); /* addu $at,$at,$ra */
2321c074d1c9Sdrahn   bfd_put_32 (input_bfd,
2322c074d1c9Sdrahn 	      (bfd_vma) 0x0020f809, location + 16); /* jalr $at */
23232159047fSniklas 
2324c074d1c9Sdrahn   return TRUE;
23252159047fSniklas }
23262159047fSniklas 
23272159047fSniklas /* Given a .sdata section and a .rel.sdata in-memory section, store
23282159047fSniklas    relocation information into the .rel.sdata section which can be
23292159047fSniklas    used at runtime to relocate the section.  This is called by the
23302159047fSniklas    linker when the --embedded-relocs switch is used.  This is called
23312159047fSniklas    after the add_symbols entry point has been called for all the
23322159047fSniklas    objects, and before the final_link entry point is called.  This
23332159047fSniklas    function presumes that the object was compiled using
23342159047fSniklas    -membedded-pic.  */
23352159047fSniklas 
2336c074d1c9Sdrahn bfd_boolean
bfd_mips_ecoff_create_embedded_relocs(abfd,info,datasec,relsec,errmsg)23372159047fSniklas bfd_mips_ecoff_create_embedded_relocs (abfd, info, datasec, relsec, errmsg)
23382159047fSniklas      bfd *abfd;
23392159047fSniklas      struct bfd_link_info *info;
23402159047fSniklas      asection *datasec;
23412159047fSniklas      asection *relsec;
23422159047fSniklas      char **errmsg;
23432159047fSniklas {
23442159047fSniklas   struct ecoff_link_hash_entry **sym_hashes;
23452159047fSniklas   struct ecoff_section_tdata *section_tdata;
23462159047fSniklas   struct external_reloc *ext_rel;
23472159047fSniklas   struct external_reloc *ext_rel_end;
23482159047fSniklas   bfd_byte *p;
2349c074d1c9Sdrahn   bfd_size_type amt;
23502159047fSniklas 
2351*007c2a45Smiod   BFD_ASSERT (! info->relocatable);
23522159047fSniklas 
23532159047fSniklas   *errmsg = NULL;
23542159047fSniklas 
23552159047fSniklas   if (datasec->reloc_count == 0)
2356c074d1c9Sdrahn     return TRUE;
23572159047fSniklas 
23582159047fSniklas   sym_hashes = ecoff_data (abfd)->sym_hashes;
23592159047fSniklas 
23602159047fSniklas   if (! mips_read_relocs (abfd, datasec))
2361c074d1c9Sdrahn     return FALSE;
23622159047fSniklas 
2363c074d1c9Sdrahn   amt = (bfd_size_type) datasec->reloc_count * 4;
2364c074d1c9Sdrahn   relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt);
23652159047fSniklas   if (relsec->contents == NULL)
2366c074d1c9Sdrahn     return FALSE;
23672159047fSniklas 
23682159047fSniklas   p = relsec->contents;
23692159047fSniklas 
23702159047fSniklas   section_tdata = ecoff_section_data (abfd, datasec);
23712159047fSniklas   ext_rel = (struct external_reloc *) section_tdata->external_relocs;
23722159047fSniklas   ext_rel_end = ext_rel + datasec->reloc_count;
23732159047fSniklas   for (; ext_rel < ext_rel_end; ext_rel++, p += 4)
23742159047fSniklas     {
23752159047fSniklas       struct internal_reloc int_rel;
2376c074d1c9Sdrahn       bfd_boolean text_relative;
23772159047fSniklas 
23782159047fSniklas       mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel);
23792159047fSniklas 
23802159047fSniklas       /* We are going to write a four byte word into the runtime reloc
23812159047fSniklas 	 section.  The word will be the address in the data section
23822159047fSniklas 	 which must be relocated.  This must be on a word boundary,
23832159047fSniklas 	 which means the lower two bits must be zero.  We use the
23842159047fSniklas 	 least significant bit to indicate how the value in the data
23852159047fSniklas 	 section must be relocated.  A 0 means that the value is
23862159047fSniklas 	 relative to the text section, while a 1 indicates that the
23872159047fSniklas 	 value is relative to the data section.  Given that we are
23882159047fSniklas 	 assuming the code was compiled using -membedded-pic, there
23892159047fSniklas 	 should not be any other possibilities.  */
23902159047fSniklas 
23912159047fSniklas       /* We can only relocate REFWORD relocs at run time.  */
23922159047fSniklas       if (int_rel.r_type != MIPS_R_REFWORD)
23932159047fSniklas 	{
2394b305b0f1Sespie 	  *errmsg = _("unsupported reloc type");
23952159047fSniklas 	  bfd_set_error (bfd_error_bad_value);
2396c074d1c9Sdrahn 	  return FALSE;
23972159047fSniklas 	}
23982159047fSniklas 
23992159047fSniklas       if (int_rel.r_extern)
24002159047fSniklas 	{
24012159047fSniklas 	  struct ecoff_link_hash_entry *h;
24022159047fSniklas 
24032159047fSniklas 	  h = sym_hashes[int_rel.r_symndx];
24042159047fSniklas 	  /* If h is NULL, that means that there is a reloc against an
24052159047fSniklas 	     external symbol which we thought was just a debugging
24062159047fSniklas 	     symbol.  This should not happen.  */
24072159047fSniklas 	  if (h == (struct ecoff_link_hash_entry *) NULL)
24082159047fSniklas 	    abort ();
24092159047fSniklas 	  if ((h->root.type == bfd_link_hash_defined
24102159047fSniklas 	       || h->root.type == bfd_link_hash_defweak)
24112159047fSniklas 	      && (h->root.u.def.section->flags & SEC_CODE) != 0)
2412c074d1c9Sdrahn 	    text_relative = TRUE;
24132159047fSniklas 	  else
2414c074d1c9Sdrahn 	    text_relative = FALSE;
24152159047fSniklas 	}
24162159047fSniklas       else
24172159047fSniklas 	{
24182159047fSniklas 	  switch (int_rel.r_symndx)
24192159047fSniklas 	    {
24202159047fSniklas 	    case RELOC_SECTION_TEXT:
2421c074d1c9Sdrahn 	      text_relative = TRUE;
24222159047fSniklas 	      break;
24232159047fSniklas 	    case RELOC_SECTION_SDATA:
24242159047fSniklas 	    case RELOC_SECTION_SBSS:
24252159047fSniklas 	    case RELOC_SECTION_LIT8:
2426c074d1c9Sdrahn 	      text_relative = FALSE;
24272159047fSniklas 	      break;
24282159047fSniklas 	    default:
24292159047fSniklas 	      /* No other sections should appear in -membedded-pic
24302159047fSniklas                  code.  */
2431b305b0f1Sespie 	      *errmsg = _("reloc against unsupported section");
24322159047fSniklas 	      bfd_set_error (bfd_error_bad_value);
2433c074d1c9Sdrahn 	      return FALSE;
24342159047fSniklas 	    }
24352159047fSniklas 	}
24362159047fSniklas 
24372159047fSniklas       if ((int_rel.r_offset & 3) != 0)
24382159047fSniklas 	{
2439b305b0f1Sespie 	  *errmsg = _("reloc not properly aligned");
24402159047fSniklas 	  bfd_set_error (bfd_error_bad_value);
2441c074d1c9Sdrahn 	  return FALSE;
24422159047fSniklas 	}
24432159047fSniklas 
24442159047fSniklas       bfd_put_32 (abfd,
24452159047fSniklas 		  (int_rel.r_vaddr - datasec->vma + datasec->output_offset
24462159047fSniklas 		   + (text_relative ? 0 : 1)),
24472159047fSniklas 		  p);
24482159047fSniklas     }
24492159047fSniklas 
2450c074d1c9Sdrahn   return TRUE;
24512159047fSniklas }
24522159047fSniklas 
24532159047fSniklas /* This is the ECOFF backend structure.  The backend field of the
24542159047fSniklas    target vector points to this.  */
24552159047fSniklas 
24562159047fSniklas static const struct ecoff_backend_data mips_ecoff_backend_data =
24572159047fSniklas {
24582159047fSniklas   /* COFF backend structure.  */
24592159047fSniklas   {
24602159047fSniklas     (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */
24612159047fSniklas     (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
24622159047fSniklas     (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */
24632159047fSniklas     (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/
24642159047fSniklas     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */
24652159047fSniklas     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */
24662159047fSniklas     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
24672159047fSniklas     mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
24682159047fSniklas     mips_ecoff_swap_scnhdr_out,
2469c074d1c9Sdrahn     FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, FALSE, 4, FALSE, 2,
24702159047fSniklas     mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
24712159047fSniklas     mips_ecoff_swap_scnhdr_in, NULL,
24722159047fSniklas     mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,
24732159047fSniklas     _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags,
24742159047fSniklas     _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table,
2475b305b0f1Sespie     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2476b305b0f1Sespie     NULL, NULL
24772159047fSniklas   },
24782159047fSniklas   /* Supported architecture.  */
24792159047fSniklas   bfd_arch_mips,
24802159047fSniklas   /* Initial portion of armap string.  */
24812159047fSniklas   "__________",
24822159047fSniklas   /* The page boundary used to align sections in a demand-paged
24832159047fSniklas      executable file.  E.g., 0x1000.  */
24842159047fSniklas   0x1000,
2485c074d1c9Sdrahn   /* TRUE if the .rdata section is part of the text segment, as on the
2486c074d1c9Sdrahn      Alpha.  FALSE if .rdata is part of the data segment, as on the
24872159047fSniklas      MIPS.  */
2488c074d1c9Sdrahn   FALSE,
24892159047fSniklas   /* Bitsize of constructor entries.  */
24902159047fSniklas   32,
24912159047fSniklas   /* Reloc to use for constructor entries.  */
24922159047fSniklas   &mips_howto_table[MIPS_R_REFWORD],
24932159047fSniklas   {
24942159047fSniklas     /* Symbol table magic number.  */
24952159047fSniklas     magicSym,
24962159047fSniklas     /* Alignment of debugging information.  E.g., 4.  */
24972159047fSniklas     4,
24982159047fSniklas     /* Sizes of external symbolic information.  */
24992159047fSniklas     sizeof (struct hdr_ext),
25002159047fSniklas     sizeof (struct dnr_ext),
25012159047fSniklas     sizeof (struct pdr_ext),
25022159047fSniklas     sizeof (struct sym_ext),
25032159047fSniklas     sizeof (struct opt_ext),
25042159047fSniklas     sizeof (struct fdr_ext),
25052159047fSniklas     sizeof (struct rfd_ext),
25062159047fSniklas     sizeof (struct ext_ext),
25072159047fSniklas     /* Functions to swap in external symbolic data.  */
25082159047fSniklas     ecoff_swap_hdr_in,
25092159047fSniklas     ecoff_swap_dnr_in,
25102159047fSniklas     ecoff_swap_pdr_in,
25112159047fSniklas     ecoff_swap_sym_in,
25122159047fSniklas     ecoff_swap_opt_in,
25132159047fSniklas     ecoff_swap_fdr_in,
25142159047fSniklas     ecoff_swap_rfd_in,
25152159047fSniklas     ecoff_swap_ext_in,
25162159047fSniklas     _bfd_ecoff_swap_tir_in,
25172159047fSniklas     _bfd_ecoff_swap_rndx_in,
25182159047fSniklas     /* Functions to swap out external symbolic data.  */
25192159047fSniklas     ecoff_swap_hdr_out,
25202159047fSniklas     ecoff_swap_dnr_out,
25212159047fSniklas     ecoff_swap_pdr_out,
25222159047fSniklas     ecoff_swap_sym_out,
25232159047fSniklas     ecoff_swap_opt_out,
25242159047fSniklas     ecoff_swap_fdr_out,
25252159047fSniklas     ecoff_swap_rfd_out,
25262159047fSniklas     ecoff_swap_ext_out,
25272159047fSniklas     _bfd_ecoff_swap_tir_out,
25282159047fSniklas     _bfd_ecoff_swap_rndx_out,
25292159047fSniklas     /* Function to read in symbolic data.  */
25302159047fSniklas     _bfd_ecoff_slurp_symbolic_info
25312159047fSniklas   },
25322159047fSniklas   /* External reloc size.  */
25332159047fSniklas   RELSZ,
25342159047fSniklas   /* Reloc swapping functions.  */
25352159047fSniklas   mips_ecoff_swap_reloc_in,
25362159047fSniklas   mips_ecoff_swap_reloc_out,
25372159047fSniklas   /* Backend reloc tweaking.  */
25382159047fSniklas   mips_adjust_reloc_in,
25392159047fSniklas   mips_adjust_reloc_out,
25402159047fSniklas   /* Relocate section contents while linking.  */
25412159047fSniklas   mips_relocate_section,
25422159047fSniklas   /* Do final adjustments to filehdr and aouthdr.  */
2543c88b1d6cSniklas   NULL,
2544c88b1d6cSniklas   /* Read an element from an archive at a given file position.  */
2545c88b1d6cSniklas   _bfd_get_elt_at_filepos
25462159047fSniklas };
25472159047fSniklas 
25482159047fSniklas /* Looking up a reloc type is MIPS specific.  */
25492159047fSniklas #define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup
25502159047fSniklas 
25512159047fSniklas /* Getting relocated section contents is generic.  */
25522159047fSniklas #define _bfd_ecoff_bfd_get_relocated_section_contents \
25532159047fSniklas   bfd_generic_get_relocated_section_contents
25542159047fSniklas 
25552159047fSniklas /* Handling file windows is generic.  */
25562159047fSniklas #define _bfd_ecoff_get_section_contents_in_window \
25572159047fSniklas   _bfd_generic_get_section_contents_in_window
25582159047fSniklas 
25592159047fSniklas /* Relaxing sections is MIPS specific.  */
25602159047fSniklas #define _bfd_ecoff_bfd_relax_section mips_relax_section
25612159047fSniklas 
2562b305b0f1Sespie /* GC of sections is not done.  */
2563b305b0f1Sespie #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
2564b305b0f1Sespie 
2565c074d1c9Sdrahn /* Merging of sections is not done.  */
2566c074d1c9Sdrahn #define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
2567c074d1c9Sdrahn 
2568c074d1c9Sdrahn #define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
2569c074d1c9Sdrahn 
2570b305b0f1Sespie extern const bfd_target ecoff_big_vec;
2571b305b0f1Sespie 
25722159047fSniklas const bfd_target ecoff_little_vec =
25732159047fSniklas {
25742159047fSniklas   "ecoff-littlemips",		/* name */
25752159047fSniklas   bfd_target_ecoff_flavour,
2576c88b1d6cSniklas   BFD_ENDIAN_LITTLE,		/* data byte order is little */
2577c88b1d6cSniklas   BFD_ENDIAN_LITTLE,		/* header byte order is little */
25782159047fSniklas 
25792159047fSniklas   (HAS_RELOC | EXEC_P |		/* object flags */
25802159047fSniklas    HAS_LINENO | HAS_DEBUG |
25812159047fSniklas    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
25822159047fSniklas 
25832159047fSniklas   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
25842159047fSniklas   0,				/* leading underscore */
25852159047fSniklas   ' ',				/* ar_pad_char */
25862159047fSniklas   15,				/* ar_max_namelen */
25872159047fSniklas   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
25882159047fSniklas      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
25892159047fSniklas      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
25902159047fSniklas   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
25912159047fSniklas      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
25922159047fSniklas      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
25932159047fSniklas 
25942159047fSniklas   {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
25952159047fSniklas      _bfd_ecoff_archive_p, _bfd_dummy_target},
25962159047fSniklas   {bfd_false, _bfd_ecoff_mkobject,  /* bfd_set_format */
25972159047fSniklas      _bfd_generic_mkarchive, bfd_false},
25982159047fSniklas   {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
25992159047fSniklas      _bfd_write_archive_contents, bfd_false},
26002159047fSniklas 
26012159047fSniklas      BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
26022159047fSniklas      BFD_JUMP_TABLE_COPY (_bfd_ecoff),
26032159047fSniklas      BFD_JUMP_TABLE_CORE (_bfd_nocore),
26042159047fSniklas      BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
26052159047fSniklas      BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
26062159047fSniklas      BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
26072159047fSniklas      BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
26082159047fSniklas      BFD_JUMP_TABLE_LINK (_bfd_ecoff),
26092159047fSniklas      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
26102159047fSniklas 
2611b305b0f1Sespie   & ecoff_big_vec,
2612b305b0f1Sespie 
26132159047fSniklas   (PTR) &mips_ecoff_backend_data
26142159047fSniklas };
26152159047fSniklas 
26162159047fSniklas const bfd_target ecoff_big_vec =
26172159047fSniklas {
26182159047fSniklas   "ecoff-bigmips",		/* name */
26192159047fSniklas   bfd_target_ecoff_flavour,
2620c88b1d6cSniklas   BFD_ENDIAN_BIG,		/* data byte order is big */
2621c88b1d6cSniklas   BFD_ENDIAN_BIG,		/* header byte order is big */
26222159047fSniklas 
26232159047fSniklas   (HAS_RELOC | EXEC_P |		/* object flags */
26242159047fSniklas    HAS_LINENO | HAS_DEBUG |
26252159047fSniklas    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
26262159047fSniklas 
26272159047fSniklas   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
26282159047fSniklas   0,				/* leading underscore */
26292159047fSniklas   ' ',				/* ar_pad_char */
26302159047fSniklas   15,				/* ar_max_namelen */
26312159047fSniklas   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
26322159047fSniklas      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
26332159047fSniklas      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
26342159047fSniklas   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
26352159047fSniklas      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
26362159047fSniklas      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
26372159047fSniklas  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
26382159047fSniklas     _bfd_ecoff_archive_p, _bfd_dummy_target},
26392159047fSniklas  {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */
26402159047fSniklas     _bfd_generic_mkarchive, bfd_false},
26412159047fSniklas  {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
26422159047fSniklas     _bfd_write_archive_contents, bfd_false},
26432159047fSniklas 
26442159047fSniklas      BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
26452159047fSniklas      BFD_JUMP_TABLE_COPY (_bfd_ecoff),
26462159047fSniklas      BFD_JUMP_TABLE_CORE (_bfd_nocore),
26472159047fSniklas      BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
26482159047fSniklas      BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
26492159047fSniklas      BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
26502159047fSniklas      BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
26512159047fSniklas      BFD_JUMP_TABLE_LINK (_bfd_ecoff),
26522159047fSniklas      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
26532159047fSniklas 
2654b305b0f1Sespie   & ecoff_little_vec,
2655b305b0f1Sespie 
2656b305b0f1Sespie   (PTR) &mips_ecoff_backend_data
2657b305b0f1Sespie };
2658b305b0f1Sespie 
2659b305b0f1Sespie const bfd_target ecoff_biglittle_vec =
2660b305b0f1Sespie {
2661b305b0f1Sespie   "ecoff-biglittlemips",		/* name */
2662b305b0f1Sespie   bfd_target_ecoff_flavour,
2663b305b0f1Sespie   BFD_ENDIAN_LITTLE,		/* data byte order is little */
2664b305b0f1Sespie   BFD_ENDIAN_BIG,		/* header byte order is big */
2665b305b0f1Sespie 
2666b305b0f1Sespie   (HAS_RELOC | EXEC_P |		/* object flags */
2667b305b0f1Sespie    HAS_LINENO | HAS_DEBUG |
2668b305b0f1Sespie    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
2669b305b0f1Sespie 
2670b305b0f1Sespie   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
2671b305b0f1Sespie   0,				/* leading underscore */
2672b305b0f1Sespie   ' ',				/* ar_pad_char */
2673b305b0f1Sespie   15,				/* ar_max_namelen */
2674b305b0f1Sespie   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
2675b305b0f1Sespie      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
2676b305b0f1Sespie      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
2677b305b0f1Sespie   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
2678b305b0f1Sespie      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
2679b305b0f1Sespie      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
2680b305b0f1Sespie 
2681b305b0f1Sespie   {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
2682b305b0f1Sespie      _bfd_ecoff_archive_p, _bfd_dummy_target},
2683b305b0f1Sespie   {bfd_false, _bfd_ecoff_mkobject,  /* bfd_set_format */
2684b305b0f1Sespie      _bfd_generic_mkarchive, bfd_false},
2685b305b0f1Sespie   {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
2686b305b0f1Sespie      _bfd_write_archive_contents, bfd_false},
2687b305b0f1Sespie 
2688b305b0f1Sespie      BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
2689b305b0f1Sespie      BFD_JUMP_TABLE_COPY (_bfd_ecoff),
2690b305b0f1Sespie      BFD_JUMP_TABLE_CORE (_bfd_nocore),
2691b305b0f1Sespie      BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
2692b305b0f1Sespie      BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
2693b305b0f1Sespie      BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
2694b305b0f1Sespie      BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
2695b305b0f1Sespie      BFD_JUMP_TABLE_LINK (_bfd_ecoff),
2696b305b0f1Sespie      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
2697b305b0f1Sespie 
2698b305b0f1Sespie   NULL,
2699b305b0f1Sespie 
27002159047fSniklas   (PTR) &mips_ecoff_backend_data
27012159047fSniklas };
2702