1179407Sobrien/* BFD back-end for MIPS Extended-Coff files.
2179407Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2004, 2007
4179407Sobrien   Free Software Foundation, Inc.
5179407Sobrien   Original version by Per Bothner.
6179407Sobrien   Full support added by Ian Lance Taylor, ian@cygnus.com.
7179407Sobrien
8179407SobrienThis file is part of BFD, the Binary File Descriptor library.
9179407Sobrien
10179407SobrienThis program is free software; you can redistribute it and/or modify
11179407Sobrienit under the terms of the GNU General Public License as published by
12179407Sobrienthe Free Software Foundation; either version 2 of the License, or
13179407Sobrien(at your option) any later version.
14179407Sobrien
15179407SobrienThis program is distributed in the hope that it will be useful,
16179407Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
17179407SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18179407SobrienGNU General Public License for more details.
19179407Sobrien
20179407SobrienYou should have received a copy of the GNU General Public License
21179407Sobrienalong with this program; if not, write to the Free Software
22218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
23179407Sobrien
24218822Sdim#include "sysdep.h"
25179407Sobrien#include "bfd.h"
26179407Sobrien#include "bfdlink.h"
27179407Sobrien#include "libbfd.h"
28179407Sobrien#include "coff/internal.h"
29179407Sobrien#include "coff/sym.h"
30179407Sobrien#include "coff/symconst.h"
31179407Sobrien#include "coff/ecoff.h"
32179407Sobrien#include "coff/mips.h"
33179407Sobrien#include "libcoff.h"
34179407Sobrien#include "libecoff.h"
35179407Sobrien
36179407Sobrien/* Prototypes for static functions.  */
37179407Sobrien
38179407Sobrienstatic bfd_boolean mips_ecoff_bad_format_hook
39179407Sobrien  PARAMS ((bfd *abfd, PTR filehdr));
40179407Sobrienstatic void mips_ecoff_swap_reloc_in
41179407Sobrien  PARAMS ((bfd *, PTR, struct internal_reloc *));
42179407Sobrienstatic void mips_ecoff_swap_reloc_out
43179407Sobrien  PARAMS ((bfd *, const struct internal_reloc *, PTR));
44179407Sobrienstatic void mips_adjust_reloc_in
45179407Sobrien  PARAMS ((bfd *, const struct internal_reloc *, arelent *));
46179407Sobrienstatic void mips_adjust_reloc_out
47179407Sobrien  PARAMS ((bfd *, const arelent *, struct internal_reloc *));
48179407Sobrienstatic bfd_reloc_status_type mips_generic_reloc
49179407Sobrien  PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
50179407Sobrien	   asection *section, bfd *output_bfd, char **error));
51179407Sobrienstatic bfd_reloc_status_type mips_refhi_reloc
52179407Sobrien  PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
53179407Sobrien	   asection *section, bfd *output_bfd, char **error));
54179407Sobrienstatic bfd_reloc_status_type mips_reflo_reloc
55179407Sobrien  PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
56179407Sobrien	   asection *section, bfd *output_bfd, char **error));
57179407Sobrienstatic bfd_reloc_status_type mips_gprel_reloc
58179407Sobrien  PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
59179407Sobrien	   asection *section, bfd *output_bfd, char **error));
60179407Sobrienstatic void mips_relocate_hi
61179407Sobrien  PARAMS ((struct internal_reloc *refhi, struct internal_reloc *reflo,
62179407Sobrien	   bfd *input_bfd, asection *input_section, bfd_byte *contents,
63218822Sdim	   bfd_vma relocation));
64179407Sobrienstatic bfd_boolean mips_relocate_section
65179407Sobrien  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PTR));
66179407Sobrienstatic reloc_howto_type *mips_bfd_reloc_type_lookup
67179407Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
68179407Sobrien
69179407Sobrien/* ECOFF has COFF sections, but the debugging information is stored in
70179407Sobrien   a completely different format.  ECOFF targets use some of the
71179407Sobrien   swapping routines from coffswap.h, and some of the generic COFF
72179407Sobrien   routines in coffgen.c, but, unlike the real COFF targets, do not
73179407Sobrien   use coffcode.h itself.
74179407Sobrien
75179407Sobrien   Get the generic COFF swapping routines, except for the reloc,
76179407Sobrien   symbol, and lineno ones.  Give them ECOFF names.  */
77179407Sobrien#define MIPSECOFF
78179407Sobrien#define NO_COFF_RELOCS
79179407Sobrien#define NO_COFF_SYMBOLS
80179407Sobrien#define NO_COFF_LINENOS
81179407Sobrien#define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in
82179407Sobrien#define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out
83179407Sobrien#define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in
84179407Sobrien#define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out
85179407Sobrien#define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in
86179407Sobrien#define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out
87179407Sobrien#include "coffswap.h"
88179407Sobrien
89179407Sobrien/* Get the ECOFF swapping routines.  */
90179407Sobrien#define ECOFF_32
91179407Sobrien#include "ecoffswap.h"
92179407Sobrien
93179407Sobrien/* How to process the various relocs types.  */
94179407Sobrien
95179407Sobrienstatic reloc_howto_type mips_howto_table[] =
96179407Sobrien{
97179407Sobrien  /* Reloc type 0 is ignored.  The reloc reading code ensures that
98179407Sobrien     this is a reference to the .abs section, which will cause
99179407Sobrien     bfd_perform_relocation to do nothing.  */
100179407Sobrien  HOWTO (MIPS_R_IGNORE,	/* type */
101179407Sobrien	 0,			/* rightshift */
102179407Sobrien	 0,			/* size (0 = byte, 1 = short, 2 = long) */
103179407Sobrien	 8,			/* bitsize */
104179407Sobrien	 FALSE,			/* pc_relative */
105179407Sobrien	 0,			/* bitpos */
106179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
107179407Sobrien	 0,			/* special_function */
108179407Sobrien	 "IGNORE",		/* name */
109179407Sobrien	 FALSE,			/* partial_inplace */
110179407Sobrien	 0,			/* src_mask */
111179407Sobrien	 0,			/* dst_mask */
112179407Sobrien	 FALSE),		/* pcrel_offset */
113179407Sobrien
114179407Sobrien  /* A 16 bit reference to a symbol, normally from a data section.  */
115179407Sobrien  HOWTO (MIPS_R_REFHALF,	/* type */
116179407Sobrien	 0,			/* rightshift */
117179407Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
118179407Sobrien	 16,			/* bitsize */
119179407Sobrien	 FALSE,			/* pc_relative */
120179407Sobrien	 0,			/* bitpos */
121179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
122179407Sobrien	 mips_generic_reloc,	/* special_function */
123179407Sobrien	 "REFHALF",		/* name */
124179407Sobrien	 TRUE,			/* partial_inplace */
125179407Sobrien	 0xffff,		/* src_mask */
126179407Sobrien	 0xffff,		/* dst_mask */
127179407Sobrien	 FALSE),		/* pcrel_offset */
128179407Sobrien
129179407Sobrien  /* A 32 bit reference to a symbol, normally from a data section.  */
130179407Sobrien  HOWTO (MIPS_R_REFWORD,	/* type */
131179407Sobrien	 0,			/* rightshift */
132179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
133179407Sobrien	 32,			/* bitsize */
134179407Sobrien	 FALSE,			/* pc_relative */
135179407Sobrien	 0,			/* bitpos */
136179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
137179407Sobrien	 mips_generic_reloc,	/* special_function */
138179407Sobrien	 "REFWORD",		/* name */
139179407Sobrien	 TRUE,			/* partial_inplace */
140179407Sobrien	 0xffffffff,		/* src_mask */
141179407Sobrien	 0xffffffff,		/* dst_mask */
142179407Sobrien	 FALSE),		/* pcrel_offset */
143179407Sobrien
144179407Sobrien  /* A 26 bit absolute jump address.  */
145179407Sobrien  HOWTO (MIPS_R_JMPADDR,	/* type */
146179407Sobrien	 2,			/* rightshift */
147179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
148179407Sobrien	 26,			/* bitsize */
149179407Sobrien	 FALSE,			/* pc_relative */
150179407Sobrien	 0,			/* bitpos */
151179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
152179407Sobrien	 			/* This needs complex overflow
153179407Sobrien				   detection, because the upper four
154179407Sobrien				   bits must match the PC.  */
155179407Sobrien	 mips_generic_reloc,	/* special_function */
156179407Sobrien	 "JMPADDR",		/* name */
157179407Sobrien	 TRUE,			/* partial_inplace */
158179407Sobrien	 0x3ffffff,		/* src_mask */
159179407Sobrien	 0x3ffffff,		/* dst_mask */
160179407Sobrien	 FALSE),		/* pcrel_offset */
161179407Sobrien
162179407Sobrien  /* The high 16 bits of a symbol value.  Handled by the function
163179407Sobrien     mips_refhi_reloc.  */
164179407Sobrien  HOWTO (MIPS_R_REFHI,		/* type */
165179407Sobrien	 16,			/* rightshift */
166179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
167179407Sobrien	 16,			/* bitsize */
168179407Sobrien	 FALSE,			/* pc_relative */
169179407Sobrien	 0,			/* bitpos */
170179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
171179407Sobrien	 mips_refhi_reloc,	/* special_function */
172179407Sobrien	 "REFHI",		/* name */
173179407Sobrien	 TRUE,			/* partial_inplace */
174179407Sobrien	 0xffff,		/* src_mask */
175179407Sobrien	 0xffff,		/* dst_mask */
176179407Sobrien	 FALSE),		/* pcrel_offset */
177179407Sobrien
178179407Sobrien  /* The low 16 bits of a symbol value.  */
179179407Sobrien  HOWTO (MIPS_R_REFLO,		/* type */
180179407Sobrien	 0,			/* rightshift */
181179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
182179407Sobrien	 16,			/* bitsize */
183179407Sobrien	 FALSE,			/* pc_relative */
184179407Sobrien	 0,			/* bitpos */
185179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
186179407Sobrien	 mips_reflo_reloc,	/* special_function */
187179407Sobrien	 "REFLO",		/* name */
188179407Sobrien	 TRUE,			/* partial_inplace */
189179407Sobrien	 0xffff,		/* src_mask */
190179407Sobrien	 0xffff,		/* dst_mask */
191179407Sobrien	 FALSE),		/* pcrel_offset */
192179407Sobrien
193179407Sobrien  /* A reference to an offset from the gp register.  Handled by the
194179407Sobrien     function mips_gprel_reloc.  */
195179407Sobrien  HOWTO (MIPS_R_GPREL,		/* type */
196179407Sobrien	 0,			/* rightshift */
197179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
198179407Sobrien	 16,			/* bitsize */
199179407Sobrien	 FALSE,			/* pc_relative */
200179407Sobrien	 0,			/* bitpos */
201179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
202179407Sobrien	 mips_gprel_reloc,	/* special_function */
203179407Sobrien	 "GPREL",		/* name */
204179407Sobrien	 TRUE,			/* partial_inplace */
205179407Sobrien	 0xffff,		/* src_mask */
206179407Sobrien	 0xffff,		/* dst_mask */
207179407Sobrien	 FALSE),		/* pcrel_offset */
208179407Sobrien
209179407Sobrien  /* A reference to a literal using an offset from the gp register.
210179407Sobrien     Handled by the function mips_gprel_reloc.  */
211179407Sobrien  HOWTO (MIPS_R_LITERAL,	/* type */
212179407Sobrien	 0,			/* rightshift */
213179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
214179407Sobrien	 16,			/* bitsize */
215179407Sobrien	 FALSE,			/* pc_relative */
216179407Sobrien	 0,			/* bitpos */
217179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
218179407Sobrien	 mips_gprel_reloc,	/* special_function */
219179407Sobrien	 "LITERAL",		/* name */
220179407Sobrien	 TRUE,			/* partial_inplace */
221179407Sobrien	 0xffff,		/* src_mask */
222179407Sobrien	 0xffff,		/* dst_mask */
223179407Sobrien	 FALSE),		/* pcrel_offset */
224179407Sobrien
225179407Sobrien  EMPTY_HOWTO (8),
226179407Sobrien  EMPTY_HOWTO (9),
227179407Sobrien  EMPTY_HOWTO (10),
228179407Sobrien  EMPTY_HOWTO (11),
229179407Sobrien
230218822Sdim  /* FIXME: This relocation is used (internally only) to represent branches
231218822Sdim     when assembling.  It should never appear in output files, and
232218822Sdim     be removed.  (It used to be used for embedded-PIC support.)  */
233179407Sobrien  HOWTO (MIPS_R_PCREL16,	/* type */
234179407Sobrien	 2,			/* rightshift */
235179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
236179407Sobrien	 16,			/* bitsize */
237179407Sobrien	 TRUE,			/* pc_relative */
238179407Sobrien	 0,			/* bitpos */
239179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
240179407Sobrien	 mips_generic_reloc,	/* special_function */
241179407Sobrien	 "PCREL16",		/* name */
242179407Sobrien	 TRUE,			/* partial_inplace */
243179407Sobrien	 0xffff,		/* src_mask */
244179407Sobrien	 0xffff,		/* dst_mask */
245179407Sobrien	 TRUE),			/* pcrel_offset */
246179407Sobrien};
247179407Sobrien
248179407Sobrien#define MIPS_HOWTO_COUNT \
249179407Sobrien  (sizeof mips_howto_table / sizeof mips_howto_table[0])
250179407Sobrien
251179407Sobrien/* See whether the magic number matches.  */
252179407Sobrien
253179407Sobrienstatic bfd_boolean
254179407Sobrienmips_ecoff_bad_format_hook (abfd, filehdr)
255179407Sobrien     bfd *abfd;
256179407Sobrien     PTR filehdr;
257179407Sobrien{
258179407Sobrien  struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
259179407Sobrien
260179407Sobrien  switch (internal_f->f_magic)
261179407Sobrien    {
262179407Sobrien    case MIPS_MAGIC_1:
263179407Sobrien      /* I don't know what endianness this implies.  */
264179407Sobrien      return TRUE;
265179407Sobrien
266179407Sobrien    case MIPS_MAGIC_BIG:
267179407Sobrien    case MIPS_MAGIC_BIG2:
268179407Sobrien    case MIPS_MAGIC_BIG3:
269179407Sobrien      return bfd_big_endian (abfd);
270179407Sobrien
271179407Sobrien    case MIPS_MAGIC_LITTLE:
272179407Sobrien    case MIPS_MAGIC_LITTLE2:
273179407Sobrien    case MIPS_MAGIC_LITTLE3:
274179407Sobrien      return bfd_little_endian (abfd);
275179407Sobrien
276179407Sobrien    default:
277179407Sobrien      return FALSE;
278179407Sobrien    }
279179407Sobrien}
280179407Sobrien
281179407Sobrien/* Reloc handling.  MIPS ECOFF relocs are packed into 8 bytes in
282179407Sobrien   external form.  They use a bit which indicates whether the symbol
283179407Sobrien   is external.  */
284179407Sobrien
285179407Sobrien/* Swap a reloc in.  */
286179407Sobrien
287179407Sobrienstatic void
288179407Sobrienmips_ecoff_swap_reloc_in (abfd, ext_ptr, intern)
289179407Sobrien     bfd *abfd;
290179407Sobrien     PTR ext_ptr;
291179407Sobrien     struct internal_reloc *intern;
292179407Sobrien{
293179407Sobrien  const RELOC *ext = (RELOC *) ext_ptr;
294179407Sobrien
295179407Sobrien  intern->r_vaddr = H_GET_32 (abfd, ext->r_vaddr);
296179407Sobrien  if (bfd_header_big_endian (abfd))
297179407Sobrien    {
298179407Sobrien      intern->r_symndx = (((int) ext->r_bits[0]
299179407Sobrien			   << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
300179407Sobrien			  | ((int) ext->r_bits[1]
301179407Sobrien			     << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
302179407Sobrien			  | ((int) ext->r_bits[2]
303179407Sobrien			     << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
304179407Sobrien      intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
305179407Sobrien			>> RELOC_BITS3_TYPE_SH_BIG);
306179407Sobrien      intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
307179407Sobrien    }
308179407Sobrien  else
309179407Sobrien    {
310179407Sobrien      intern->r_symndx = (((int) ext->r_bits[0]
311179407Sobrien			   << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
312179407Sobrien			  | ((int) ext->r_bits[1]
313179407Sobrien			     << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
314179407Sobrien			  | ((int) ext->r_bits[2]
315179407Sobrien			     << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
316179407Sobrien      intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
317179407Sobrien			 >> RELOC_BITS3_TYPE_SH_LITTLE)
318179407Sobrien			| ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE)
319179407Sobrien			   << RELOC_BITS3_TYPEHI_SH_LITTLE));
320179407Sobrien      intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
321179407Sobrien    }
322179407Sobrien}
323179407Sobrien
324179407Sobrien/* Swap a reloc out.  */
325179407Sobrien
326179407Sobrienstatic void
327179407Sobrienmips_ecoff_swap_reloc_out (abfd, intern, dst)
328179407Sobrien     bfd *abfd;
329179407Sobrien     const struct internal_reloc *intern;
330179407Sobrien     PTR dst;
331179407Sobrien{
332179407Sobrien  RELOC *ext = (RELOC *) dst;
333179407Sobrien  long r_symndx;
334179407Sobrien
335179407Sobrien  BFD_ASSERT (intern->r_extern
336179407Sobrien	      || (intern->r_symndx >= 0 && intern->r_symndx <= 12));
337179407Sobrien
338218822Sdim  r_symndx = intern->r_symndx;
339179407Sobrien
340179407Sobrien  H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr);
341179407Sobrien  if (bfd_header_big_endian (abfd))
342179407Sobrien    {
343179407Sobrien      ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
344179407Sobrien      ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
345179407Sobrien      ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
346179407Sobrien      ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
347179407Sobrien			 & RELOC_BITS3_TYPE_BIG)
348179407Sobrien			| (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
349179407Sobrien    }
350179407Sobrien  else
351179407Sobrien    {
352179407Sobrien      ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
353179407Sobrien      ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
354179407Sobrien      ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
355179407Sobrien      ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
356179407Sobrien			 & RELOC_BITS3_TYPE_LITTLE)
357179407Sobrien			| ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE
358179407Sobrien			    & RELOC_BITS3_TYPEHI_LITTLE))
359179407Sobrien			| (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
360179407Sobrien    }
361179407Sobrien}
362179407Sobrien
363179407Sobrien/* Finish canonicalizing a reloc.  Part of this is generic to all
364179407Sobrien   ECOFF targets, and that part is in ecoff.c.  The rest is done in
365179407Sobrien   this backend routine.  It must fill in the howto field.  */
366179407Sobrien
367179407Sobrienstatic void
368179407Sobrienmips_adjust_reloc_in (abfd, intern, rptr)
369179407Sobrien     bfd *abfd;
370179407Sobrien     const struct internal_reloc *intern;
371179407Sobrien     arelent *rptr;
372179407Sobrien{
373218822Sdim  if (intern->r_type > MIPS_R_PCREL16)
374179407Sobrien    abort ();
375179407Sobrien
376179407Sobrien  if (! intern->r_extern
377179407Sobrien      && (intern->r_type == MIPS_R_GPREL
378179407Sobrien	  || intern->r_type == MIPS_R_LITERAL))
379179407Sobrien    rptr->addend += ecoff_data (abfd)->gp;
380179407Sobrien
381179407Sobrien  /* If the type is MIPS_R_IGNORE, make sure this is a reference to
382179407Sobrien     the absolute section so that the reloc is ignored.  */
383179407Sobrien  if (intern->r_type == MIPS_R_IGNORE)
384179407Sobrien    rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
385179407Sobrien
386179407Sobrien  rptr->howto = &mips_howto_table[intern->r_type];
387179407Sobrien}
388179407Sobrien
389179407Sobrien/* Make any adjustments needed to a reloc before writing it out.  None
390179407Sobrien   are needed for MIPS.  */
391179407Sobrien
392179407Sobrienstatic void
393179407Sobrienmips_adjust_reloc_out (abfd, rel, intern)
394179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
395218822Sdim     const arelent *rel ATTRIBUTE_UNUSED;
396218822Sdim     struct internal_reloc *intern ATTRIBUTE_UNUSED;
397179407Sobrien{
398179407Sobrien}
399179407Sobrien
400179407Sobrien/* ECOFF relocs are either against external symbols, or against
401179407Sobrien   sections.  If we are producing relocatable output, and the reloc
402179407Sobrien   is against an external symbol, and nothing has given us any
403179407Sobrien   additional addend, the resulting reloc will also be against the
404179407Sobrien   same symbol.  In such a case, we don't want to change anything
405179407Sobrien   about the way the reloc is handled, since it will all be done at
406179407Sobrien   final link time.  Rather than put special case code into
407179407Sobrien   bfd_perform_relocation, all the reloc types use this howto
408179407Sobrien   function.  It just short circuits the reloc if producing
409179407Sobrien   relocatable output against an external symbol.  */
410179407Sobrien
411179407Sobrienstatic bfd_reloc_status_type
412179407Sobrienmips_generic_reloc (abfd,
413179407Sobrien		    reloc_entry,
414179407Sobrien		    symbol,
415179407Sobrien		    data,
416179407Sobrien		    input_section,
417179407Sobrien		    output_bfd,
418179407Sobrien		    error_message)
419179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
420179407Sobrien     arelent *reloc_entry;
421179407Sobrien     asymbol *symbol;
422179407Sobrien     PTR data ATTRIBUTE_UNUSED;
423179407Sobrien     asection *input_section;
424179407Sobrien     bfd *output_bfd;
425179407Sobrien     char **error_message ATTRIBUTE_UNUSED;
426179407Sobrien{
427179407Sobrien  if (output_bfd != (bfd *) NULL
428179407Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0
429179407Sobrien      && reloc_entry->addend == 0)
430179407Sobrien    {
431179407Sobrien      reloc_entry->address += input_section->output_offset;
432179407Sobrien      return bfd_reloc_ok;
433179407Sobrien    }
434179407Sobrien
435179407Sobrien  return bfd_reloc_continue;
436179407Sobrien}
437179407Sobrien
438179407Sobrien/* Do a REFHI relocation.  This has to be done in combination with a
439179407Sobrien   REFLO reloc, because there is a carry from the REFLO to the REFHI.
440179407Sobrien   Here we just save the information we need; we do the actual
441179407Sobrien   relocation when we see the REFLO.  MIPS ECOFF requires that the
442179407Sobrien   REFLO immediately follow the REFHI.  As a GNU extension, we permit
443179407Sobrien   an arbitrary number of HI relocs to be associated with a single LO
444179407Sobrien   reloc.  This extension permits gcc to output the HI and LO relocs
445179407Sobrien   itself.  */
446179407Sobrien
447179407Sobrienstruct mips_hi
448179407Sobrien{
449179407Sobrien  struct mips_hi *next;
450179407Sobrien  bfd_byte *addr;
451179407Sobrien  bfd_vma addend;
452179407Sobrien};
453179407Sobrien
454179407Sobrien/* FIXME: This should not be a static variable.  */
455179407Sobrien
456179407Sobrienstatic struct mips_hi *mips_refhi_list;
457179407Sobrien
458179407Sobrienstatic bfd_reloc_status_type
459179407Sobrienmips_refhi_reloc (abfd,
460179407Sobrien		  reloc_entry,
461179407Sobrien		  symbol,
462179407Sobrien		  data,
463179407Sobrien		  input_section,
464179407Sobrien		  output_bfd,
465179407Sobrien		  error_message)
466179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
467179407Sobrien     arelent *reloc_entry;
468179407Sobrien     asymbol *symbol;
469179407Sobrien     PTR data;
470179407Sobrien     asection *input_section;
471179407Sobrien     bfd *output_bfd;
472179407Sobrien     char **error_message ATTRIBUTE_UNUSED;
473179407Sobrien{
474179407Sobrien  bfd_reloc_status_type ret;
475179407Sobrien  bfd_vma relocation;
476179407Sobrien  struct mips_hi *n;
477179407Sobrien
478179407Sobrien  /* If we're relocating, and this an external symbol, we don't want
479179407Sobrien     to change anything.  */
480179407Sobrien  if (output_bfd != (bfd *) NULL
481179407Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0
482179407Sobrien      && reloc_entry->addend == 0)
483179407Sobrien    {
484179407Sobrien      reloc_entry->address += input_section->output_offset;
485179407Sobrien      return bfd_reloc_ok;
486179407Sobrien    }
487179407Sobrien
488179407Sobrien  ret = bfd_reloc_ok;
489179407Sobrien  if (bfd_is_und_section (symbol->section)
490179407Sobrien      && output_bfd == (bfd *) NULL)
491179407Sobrien    ret = bfd_reloc_undefined;
492179407Sobrien
493179407Sobrien  if (bfd_is_com_section (symbol->section))
494179407Sobrien    relocation = 0;
495179407Sobrien  else
496179407Sobrien    relocation = symbol->value;
497179407Sobrien
498179407Sobrien  relocation += symbol->section->output_section->vma;
499179407Sobrien  relocation += symbol->section->output_offset;
500179407Sobrien  relocation += reloc_entry->addend;
501179407Sobrien
502218822Sdim  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
503179407Sobrien    return bfd_reloc_outofrange;
504179407Sobrien
505179407Sobrien  /* Save the information, and let REFLO do the actual relocation.  */
506179407Sobrien  n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
507179407Sobrien  if (n == NULL)
508179407Sobrien    return bfd_reloc_outofrange;
509179407Sobrien  n->addr = (bfd_byte *) data + reloc_entry->address;
510179407Sobrien  n->addend = relocation;
511179407Sobrien  n->next = mips_refhi_list;
512179407Sobrien  mips_refhi_list = n;
513179407Sobrien
514179407Sobrien  if (output_bfd != (bfd *) NULL)
515179407Sobrien    reloc_entry->address += input_section->output_offset;
516179407Sobrien
517179407Sobrien  return ret;
518179407Sobrien}
519179407Sobrien
520179407Sobrien/* Do a REFLO relocation.  This is a straightforward 16 bit inplace
521179407Sobrien   relocation; this function exists in order to do the REFHI
522179407Sobrien   relocation described above.  */
523179407Sobrien
524179407Sobrienstatic bfd_reloc_status_type
525179407Sobrienmips_reflo_reloc (abfd,
526179407Sobrien		  reloc_entry,
527179407Sobrien		  symbol,
528179407Sobrien		  data,
529179407Sobrien		  input_section,
530179407Sobrien		  output_bfd,
531179407Sobrien		  error_message)
532179407Sobrien     bfd *abfd;
533179407Sobrien     arelent *reloc_entry;
534179407Sobrien     asymbol *symbol;
535179407Sobrien     PTR data;
536179407Sobrien     asection *input_section;
537179407Sobrien     bfd *output_bfd;
538179407Sobrien     char **error_message;
539179407Sobrien{
540179407Sobrien  if (mips_refhi_list != NULL)
541179407Sobrien    {
542179407Sobrien      struct mips_hi *l;
543179407Sobrien
544179407Sobrien      l = mips_refhi_list;
545179407Sobrien      while (l != NULL)
546179407Sobrien	{
547179407Sobrien	  unsigned long insn;
548179407Sobrien	  unsigned long val;
549179407Sobrien	  unsigned long vallo;
550179407Sobrien	  struct mips_hi *next;
551179407Sobrien
552179407Sobrien	  /* Do the REFHI relocation.  Note that we actually don't
553179407Sobrien	     need to know anything about the REFLO itself, except
554179407Sobrien	     where to find the low 16 bits of the addend needed by the
555179407Sobrien	     REFHI.  */
556179407Sobrien	  insn = bfd_get_32 (abfd, l->addr);
557179407Sobrien	  vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
558179407Sobrien		   & 0xffff);
559179407Sobrien	  val = ((insn & 0xffff) << 16) + vallo;
560179407Sobrien	  val += l->addend;
561179407Sobrien
562179407Sobrien	  /* The low order 16 bits are always treated as a signed
563179407Sobrien	     value.  Therefore, a negative value in the low order bits
564179407Sobrien	     requires an adjustment in the high order bits.  We need
565179407Sobrien	     to make this adjustment in two ways: once for the bits we
566179407Sobrien	     took from the data, and once for the bits we are putting
567179407Sobrien	     back in to the data.  */
568179407Sobrien	  if ((vallo & 0x8000) != 0)
569179407Sobrien	    val -= 0x10000;
570179407Sobrien	  if ((val & 0x8000) != 0)
571179407Sobrien	    val += 0x10000;
572179407Sobrien
573179407Sobrien	  insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
574179407Sobrien	  bfd_put_32 (abfd, (bfd_vma) insn, l->addr);
575179407Sobrien
576179407Sobrien	  next = l->next;
577179407Sobrien	  free (l);
578179407Sobrien	  l = next;
579179407Sobrien	}
580179407Sobrien
581179407Sobrien      mips_refhi_list = NULL;
582179407Sobrien    }
583179407Sobrien
584179407Sobrien  /* Now do the REFLO reloc in the usual way.  */
585179407Sobrien  return mips_generic_reloc (abfd, reloc_entry, symbol, data,
586179407Sobrien			      input_section, output_bfd, error_message);
587179407Sobrien}
588179407Sobrien
589179407Sobrien/* Do a GPREL relocation.  This is a 16 bit value which must become
590179407Sobrien   the offset from the gp register.  */
591179407Sobrien
592179407Sobrienstatic bfd_reloc_status_type
593179407Sobrienmips_gprel_reloc (abfd,
594179407Sobrien		  reloc_entry,
595179407Sobrien		  symbol,
596179407Sobrien		  data,
597179407Sobrien		  input_section,
598179407Sobrien		  output_bfd,
599179407Sobrien		  error_message)
600179407Sobrien     bfd *abfd;
601179407Sobrien     arelent *reloc_entry;
602179407Sobrien     asymbol *symbol;
603179407Sobrien     PTR data;
604179407Sobrien     asection *input_section;
605179407Sobrien     bfd *output_bfd;
606179407Sobrien     char **error_message;
607179407Sobrien{
608179407Sobrien  bfd_boolean relocatable;
609179407Sobrien  bfd_vma gp;
610179407Sobrien  bfd_vma relocation;
611179407Sobrien  unsigned long val;
612179407Sobrien  unsigned long insn;
613179407Sobrien
614179407Sobrien  /* If we're relocating, and this is an external symbol with no
615179407Sobrien     addend, we don't want to change anything.  We will only have an
616179407Sobrien     addend if this is a newly created reloc, not read from an ECOFF
617179407Sobrien     file.  */
618179407Sobrien  if (output_bfd != (bfd *) NULL
619179407Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0
620179407Sobrien      && reloc_entry->addend == 0)
621179407Sobrien    {
622179407Sobrien      reloc_entry->address += input_section->output_offset;
623179407Sobrien      return bfd_reloc_ok;
624179407Sobrien    }
625179407Sobrien
626179407Sobrien  if (output_bfd != (bfd *) NULL)
627179407Sobrien    relocatable = TRUE;
628179407Sobrien  else
629179407Sobrien    {
630179407Sobrien      relocatable = FALSE;
631179407Sobrien      output_bfd = symbol->section->output_section->owner;
632179407Sobrien    }
633179407Sobrien
634179407Sobrien  if (bfd_is_und_section (symbol->section) && ! relocatable)
635179407Sobrien    return bfd_reloc_undefined;
636179407Sobrien
637179407Sobrien  /* We have to figure out the gp value, so that we can adjust the
638179407Sobrien     symbol value correctly.  We look up the symbol _gp in the output
639179407Sobrien     BFD.  If we can't find it, we're stuck.  We cache it in the ECOFF
640179407Sobrien     target data.  We don't need to adjust the symbol value for an
641179407Sobrien     external symbol if we are producing relocatable output.  */
642179407Sobrien  gp = _bfd_get_gp_value (output_bfd);
643179407Sobrien  if (gp == 0
644179407Sobrien      && (! relocatable
645179407Sobrien	  || (symbol->flags & BSF_SECTION_SYM) != 0))
646179407Sobrien    {
647179407Sobrien      if (relocatable)
648179407Sobrien	{
649179407Sobrien	  /* Make up a value.  */
650179407Sobrien	  gp = symbol->section->output_section->vma + 0x4000;
651179407Sobrien	  _bfd_set_gp_value (output_bfd, gp);
652179407Sobrien	}
653179407Sobrien      else
654179407Sobrien	{
655179407Sobrien	  unsigned int count;
656179407Sobrien	  asymbol **sym;
657179407Sobrien	  unsigned int i;
658179407Sobrien
659179407Sobrien	  count = bfd_get_symcount (output_bfd);
660179407Sobrien	  sym = bfd_get_outsymbols (output_bfd);
661179407Sobrien
662179407Sobrien	  if (sym == (asymbol **) NULL)
663179407Sobrien	    i = count;
664179407Sobrien	  else
665179407Sobrien	    {
666179407Sobrien	      for (i = 0; i < count; i++, sym++)
667179407Sobrien		{
668179407Sobrien		  register const char *name;
669179407Sobrien
670179407Sobrien		  name = bfd_asymbol_name (*sym);
671179407Sobrien		  if (*name == '_' && strcmp (name, "_gp") == 0)
672179407Sobrien		    {
673179407Sobrien		      gp = bfd_asymbol_value (*sym);
674179407Sobrien		      _bfd_set_gp_value (output_bfd, gp);
675179407Sobrien		      break;
676179407Sobrien		    }
677179407Sobrien		}
678179407Sobrien	    }
679179407Sobrien
680179407Sobrien	  if (i >= count)
681179407Sobrien	    {
682179407Sobrien	      /* Only get the error once.  */
683179407Sobrien	      gp = 4;
684179407Sobrien	      _bfd_set_gp_value (output_bfd, gp);
685179407Sobrien	      *error_message =
686179407Sobrien		(char *) _("GP relative relocation when _gp not defined");
687179407Sobrien	      return bfd_reloc_dangerous;
688179407Sobrien	    }
689179407Sobrien	}
690179407Sobrien    }
691179407Sobrien
692179407Sobrien  if (bfd_is_com_section (symbol->section))
693179407Sobrien    relocation = 0;
694179407Sobrien  else
695179407Sobrien    relocation = symbol->value;
696179407Sobrien
697179407Sobrien  relocation += symbol->section->output_section->vma;
698179407Sobrien  relocation += symbol->section->output_offset;
699179407Sobrien
700218822Sdim  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
701179407Sobrien    return bfd_reloc_outofrange;
702179407Sobrien
703179407Sobrien  insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
704179407Sobrien
705179407Sobrien  /* Set val to the offset into the section or symbol.  */
706179407Sobrien  val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
707179407Sobrien  if (val & 0x8000)
708179407Sobrien    val -= 0x10000;
709179407Sobrien
710179407Sobrien  /* Adjust val for the final section location and GP value.  If we
711179407Sobrien     are producing relocatable output, we don't want to do this for
712179407Sobrien     an external symbol.  */
713179407Sobrien  if (! relocatable
714179407Sobrien      || (symbol->flags & BSF_SECTION_SYM) != 0)
715179407Sobrien    val += relocation - gp;
716179407Sobrien
717179407Sobrien  insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff);
718179407Sobrien  bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);
719179407Sobrien
720179407Sobrien  if (relocatable)
721179407Sobrien    reloc_entry->address += input_section->output_offset;
722179407Sobrien
723179407Sobrien  /* Make sure it fit in 16 bits.  */
724179407Sobrien  if ((long) val >= 0x8000 || (long) val < -0x8000)
725179407Sobrien    return bfd_reloc_overflow;
726179407Sobrien
727179407Sobrien  return bfd_reloc_ok;
728179407Sobrien}
729179407Sobrien
730179407Sobrien/* Get the howto structure for a generic reloc type.  */
731179407Sobrien
732179407Sobrienstatic reloc_howto_type *
733179407Sobrienmips_bfd_reloc_type_lookup (abfd, code)
734179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
735179407Sobrien     bfd_reloc_code_real_type code;
736179407Sobrien{
737179407Sobrien  int mips_type;
738179407Sobrien
739179407Sobrien  switch (code)
740179407Sobrien    {
741179407Sobrien    case BFD_RELOC_16:
742179407Sobrien      mips_type = MIPS_R_REFHALF;
743179407Sobrien      break;
744179407Sobrien    case BFD_RELOC_32:
745179407Sobrien    case BFD_RELOC_CTOR:
746179407Sobrien      mips_type = MIPS_R_REFWORD;
747179407Sobrien      break;
748179407Sobrien    case BFD_RELOC_MIPS_JMP:
749179407Sobrien      mips_type = MIPS_R_JMPADDR;
750179407Sobrien      break;
751179407Sobrien    case BFD_RELOC_HI16_S:
752179407Sobrien      mips_type = MIPS_R_REFHI;
753179407Sobrien      break;
754179407Sobrien    case BFD_RELOC_LO16:
755179407Sobrien      mips_type = MIPS_R_REFLO;
756179407Sobrien      break;
757179407Sobrien    case BFD_RELOC_GPREL16:
758179407Sobrien      mips_type = MIPS_R_GPREL;
759179407Sobrien      break;
760179407Sobrien    case BFD_RELOC_MIPS_LITERAL:
761179407Sobrien      mips_type = MIPS_R_LITERAL;
762179407Sobrien      break;
763179407Sobrien    case BFD_RELOC_16_PCREL_S2:
764179407Sobrien      mips_type = MIPS_R_PCREL16;
765179407Sobrien      break;
766179407Sobrien    default:
767179407Sobrien      return (reloc_howto_type *) NULL;
768179407Sobrien    }
769179407Sobrien
770179407Sobrien  return &mips_howto_table[mips_type];
771179407Sobrien}
772218822Sdim
773218822Sdimstatic reloc_howto_type *
774218822Sdimmips_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
775218822Sdim			    const char *r_name)
776218822Sdim{
777218822Sdim  unsigned int i;
778218822Sdim
779218822Sdim  for (i = 0;
780218822Sdim       i < sizeof (mips_howto_table) / sizeof (mips_howto_table[0]);
781218822Sdim       i++)
782218822Sdim    if (mips_howto_table[i].name != NULL
783218822Sdim	&& strcasecmp (mips_howto_table[i].name, r_name) == 0)
784218822Sdim      return &mips_howto_table[i];
785218822Sdim
786218822Sdim  return NULL;
787218822Sdim}
788179407Sobrien
789179407Sobrien/* A helper routine for mips_relocate_section which handles the REFHI
790218822Sdim   relocations.  The REFHI relocation must be followed by a REFLO
791218822Sdim   relocation, and the addend used is formed from the addends of both
792218822Sdim   instructions.  */
793179407Sobrien
794179407Sobrienstatic void
795218822Sdimmips_relocate_hi (refhi, reflo, input_bfd, input_section, contents,
796218822Sdim		  relocation)
797179407Sobrien     struct internal_reloc *refhi;
798179407Sobrien     struct internal_reloc *reflo;
799179407Sobrien     bfd *input_bfd;
800179407Sobrien     asection *input_section;
801179407Sobrien     bfd_byte *contents;
802179407Sobrien     bfd_vma relocation;
803179407Sobrien{
804179407Sobrien  unsigned long insn;
805179407Sobrien  unsigned long val;
806179407Sobrien  unsigned long vallo;
807179407Sobrien
808179407Sobrien  if (refhi == NULL)
809179407Sobrien    return;
810179407Sobrien
811179407Sobrien  insn = bfd_get_32 (input_bfd,
812218822Sdim		     contents + refhi->r_vaddr - input_section->vma);
813179407Sobrien  if (reflo == NULL)
814179407Sobrien    vallo = 0;
815179407Sobrien  else
816179407Sobrien    vallo = (bfd_get_32 (input_bfd,
817218822Sdim			 contents + reflo->r_vaddr - input_section->vma)
818179407Sobrien	     & 0xffff);
819179407Sobrien
820179407Sobrien  val = ((insn & 0xffff) << 16) + vallo;
821179407Sobrien  val += relocation;
822179407Sobrien
823179407Sobrien  /* The low order 16 bits are always treated as a signed value.
824179407Sobrien     Therefore, a negative value in the low order bits requires an
825179407Sobrien     adjustment in the high order bits.  We need to make this
826179407Sobrien     adjustment in two ways: once for the bits we took from the data,
827179407Sobrien     and once for the bits we are putting back in to the data.  */
828179407Sobrien  if ((vallo & 0x8000) != 0)
829179407Sobrien    val -= 0x10000;
830179407Sobrien
831179407Sobrien  if ((val & 0x8000) != 0)
832179407Sobrien    val += 0x10000;
833179407Sobrien
834179407Sobrien  insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
835179407Sobrien  bfd_put_32 (input_bfd, (bfd_vma) insn,
836218822Sdim	      contents + refhi->r_vaddr - input_section->vma);
837179407Sobrien}
838179407Sobrien
839179407Sobrien/* Relocate a section while linking a MIPS ECOFF file.  */
840179407Sobrien
841179407Sobrienstatic bfd_boolean
842179407Sobrienmips_relocate_section (output_bfd, info, input_bfd, input_section,
843179407Sobrien		       contents, external_relocs)
844179407Sobrien     bfd *output_bfd;
845179407Sobrien     struct bfd_link_info *info;
846179407Sobrien     bfd *input_bfd;
847179407Sobrien     asection *input_section;
848179407Sobrien     bfd_byte *contents;
849179407Sobrien     PTR external_relocs;
850179407Sobrien{
851179407Sobrien  asection **symndx_to_section;
852179407Sobrien  struct ecoff_link_hash_entry **sym_hashes;
853179407Sobrien  bfd_vma gp;
854179407Sobrien  bfd_boolean gp_undefined;
855179407Sobrien  struct external_reloc *ext_rel;
856179407Sobrien  struct external_reloc *ext_rel_end;
857179407Sobrien  unsigned int i;
858179407Sobrien  bfd_boolean got_lo;
859179407Sobrien  struct internal_reloc lo_int_rel;
860179407Sobrien  bfd_size_type amt;
861179407Sobrien
862179407Sobrien  BFD_ASSERT (input_bfd->xvec->byteorder
863179407Sobrien	      == output_bfd->xvec->byteorder);
864179407Sobrien
865179407Sobrien  /* We keep a table mapping the symndx found in an internal reloc to
866179407Sobrien     the appropriate section.  This is faster than looking up the
867179407Sobrien     section by name each time.  */
868179407Sobrien  symndx_to_section = ecoff_data (input_bfd)->symndx_to_section;
869179407Sobrien  if (symndx_to_section == (asection **) NULL)
870179407Sobrien    {
871179407Sobrien      amt = NUM_RELOC_SECTIONS * sizeof (asection *);
872179407Sobrien      symndx_to_section = (asection **) bfd_alloc (input_bfd, amt);
873179407Sobrien      if (!symndx_to_section)
874179407Sobrien	return FALSE;
875179407Sobrien
876179407Sobrien      symndx_to_section[RELOC_SECTION_NONE] = NULL;
877179407Sobrien      symndx_to_section[RELOC_SECTION_TEXT] =
878179407Sobrien	bfd_get_section_by_name (input_bfd, ".text");
879179407Sobrien      symndx_to_section[RELOC_SECTION_RDATA] =
880179407Sobrien	bfd_get_section_by_name (input_bfd, ".rdata");
881179407Sobrien      symndx_to_section[RELOC_SECTION_DATA] =
882179407Sobrien	bfd_get_section_by_name (input_bfd, ".data");
883179407Sobrien      symndx_to_section[RELOC_SECTION_SDATA] =
884179407Sobrien	bfd_get_section_by_name (input_bfd, ".sdata");
885179407Sobrien      symndx_to_section[RELOC_SECTION_SBSS] =
886179407Sobrien	bfd_get_section_by_name (input_bfd, ".sbss");
887179407Sobrien      symndx_to_section[RELOC_SECTION_BSS] =
888179407Sobrien	bfd_get_section_by_name (input_bfd, ".bss");
889179407Sobrien      symndx_to_section[RELOC_SECTION_INIT] =
890179407Sobrien	bfd_get_section_by_name (input_bfd, ".init");
891179407Sobrien      symndx_to_section[RELOC_SECTION_LIT8] =
892179407Sobrien	bfd_get_section_by_name (input_bfd, ".lit8");
893179407Sobrien      symndx_to_section[RELOC_SECTION_LIT4] =
894179407Sobrien	bfd_get_section_by_name (input_bfd, ".lit4");
895179407Sobrien      symndx_to_section[RELOC_SECTION_XDATA] = NULL;
896179407Sobrien      symndx_to_section[RELOC_SECTION_PDATA] = NULL;
897179407Sobrien      symndx_to_section[RELOC_SECTION_FINI] =
898179407Sobrien	bfd_get_section_by_name (input_bfd, ".fini");
899179407Sobrien      symndx_to_section[RELOC_SECTION_LITA] = NULL;
900179407Sobrien      symndx_to_section[RELOC_SECTION_ABS] = NULL;
901179407Sobrien
902179407Sobrien      ecoff_data (input_bfd)->symndx_to_section = symndx_to_section;
903179407Sobrien    }
904179407Sobrien
905179407Sobrien  sym_hashes = ecoff_data (input_bfd)->sym_hashes;
906179407Sobrien
907179407Sobrien  gp = _bfd_get_gp_value (output_bfd);
908179407Sobrien  if (gp == 0)
909179407Sobrien    gp_undefined = TRUE;
910179407Sobrien  else
911179407Sobrien    gp_undefined = FALSE;
912179407Sobrien
913179407Sobrien  got_lo = FALSE;
914179407Sobrien
915179407Sobrien  ext_rel = (struct external_reloc *) external_relocs;
916179407Sobrien  ext_rel_end = ext_rel + input_section->reloc_count;
917179407Sobrien  for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
918179407Sobrien    {
919179407Sobrien      struct internal_reloc int_rel;
920179407Sobrien      bfd_boolean use_lo = FALSE;
921179407Sobrien      bfd_vma addend;
922179407Sobrien      reloc_howto_type *howto;
923179407Sobrien      struct ecoff_link_hash_entry *h = NULL;
924179407Sobrien      asection *s = NULL;
925179407Sobrien      bfd_vma relocation;
926179407Sobrien      bfd_reloc_status_type r;
927179407Sobrien
928179407Sobrien      if (! got_lo)
929179407Sobrien	mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel);
930179407Sobrien      else
931179407Sobrien	{
932179407Sobrien	  int_rel = lo_int_rel;
933179407Sobrien	  got_lo = FALSE;
934179407Sobrien	}
935179407Sobrien
936179407Sobrien      BFD_ASSERT (int_rel.r_type
937179407Sobrien		  < sizeof mips_howto_table / sizeof mips_howto_table[0]);
938179407Sobrien
939218822Sdim      /* The REFHI reloc requires special handling.  It must be followed
940218822Sdim	 by a REFLO reloc, and the addend is formed from both relocs.  */
941218822Sdim      if (int_rel.r_type == MIPS_R_REFHI)
942179407Sobrien	{
943179407Sobrien	  struct external_reloc *lo_ext_rel;
944179407Sobrien
945179407Sobrien	  /* As a GNU extension, permit an arbitrary number of REFHI
946218822Sdim             relocs before the REFLO reloc.  This permits gcc to emit
947218822Sdim	     the HI and LO relocs itself.  */
948179407Sobrien	  for (lo_ext_rel = ext_rel + 1;
949179407Sobrien	       lo_ext_rel < ext_rel_end;
950179407Sobrien	       lo_ext_rel++)
951179407Sobrien	    {
952179407Sobrien	      mips_ecoff_swap_reloc_in (input_bfd, (PTR) lo_ext_rel,
953179407Sobrien					&lo_int_rel);
954179407Sobrien	      if (lo_int_rel.r_type != int_rel.r_type)
955179407Sobrien		break;
956179407Sobrien	    }
957179407Sobrien
958179407Sobrien	  if (lo_ext_rel < ext_rel_end
959218822Sdim	      && lo_int_rel.r_type == MIPS_R_REFLO
960179407Sobrien	      && int_rel.r_extern == lo_int_rel.r_extern
961179407Sobrien	      && int_rel.r_symndx == lo_int_rel.r_symndx)
962179407Sobrien	    {
963179407Sobrien	      use_lo = TRUE;
964179407Sobrien	      if (lo_ext_rel == ext_rel + 1)
965179407Sobrien		got_lo = TRUE;
966179407Sobrien	    }
967179407Sobrien	}
968179407Sobrien
969179407Sobrien      howto = &mips_howto_table[int_rel.r_type];
970179407Sobrien
971179407Sobrien      if (int_rel.r_extern)
972179407Sobrien	{
973179407Sobrien	  h = sym_hashes[int_rel.r_symndx];
974179407Sobrien	  /* If h is NULL, that means that there is a reloc against an
975179407Sobrien	     external symbol which we thought was just a debugging
976179407Sobrien	     symbol.  This should not happen.  */
977179407Sobrien	  if (h == (struct ecoff_link_hash_entry *) NULL)
978179407Sobrien	    abort ();
979179407Sobrien	}
980179407Sobrien      else
981179407Sobrien	{
982179407Sobrien	  if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS)
983179407Sobrien	    s = NULL;
984179407Sobrien	  else
985179407Sobrien	    s = symndx_to_section[int_rel.r_symndx];
986179407Sobrien
987179407Sobrien	  if (s == (asection *) NULL)
988179407Sobrien	    abort ();
989179407Sobrien	}
990179407Sobrien
991179407Sobrien      /* The GPREL reloc uses an addend: the difference in the GP
992179407Sobrien	 values.  */
993179407Sobrien      if (int_rel.r_type != MIPS_R_GPREL
994179407Sobrien	  && int_rel.r_type != MIPS_R_LITERAL)
995179407Sobrien	addend = 0;
996179407Sobrien      else
997179407Sobrien	{
998179407Sobrien	  if (gp_undefined)
999179407Sobrien	    {
1000179407Sobrien	      if (! ((*info->callbacks->reloc_dangerous)
1001179407Sobrien		     (info, _("GP relative relocation used when GP not defined"),
1002179407Sobrien		      input_bfd, input_section,
1003179407Sobrien		      int_rel.r_vaddr - input_section->vma)))
1004179407Sobrien		return FALSE;
1005179407Sobrien	      /* Only give the error once per link.  */
1006179407Sobrien	      gp = 4;
1007179407Sobrien	      _bfd_set_gp_value (output_bfd, gp);
1008179407Sobrien	      gp_undefined = FALSE;
1009179407Sobrien	    }
1010179407Sobrien	  if (! int_rel.r_extern)
1011179407Sobrien	    {
1012179407Sobrien	      /* This is a relocation against a section.  The current
1013179407Sobrien		 addend in the instruction is the difference between
1014179407Sobrien		 INPUT_SECTION->vma and the GP value of INPUT_BFD.  We
1015179407Sobrien		 must change this to be the difference between the
1016179407Sobrien		 final definition (which will end up in RELOCATION)
1017179407Sobrien		 and the GP value of OUTPUT_BFD (which is in GP).  */
1018179407Sobrien	      addend = ecoff_data (input_bfd)->gp - gp;
1019179407Sobrien	    }
1020179407Sobrien	  else if (! info->relocatable
1021179407Sobrien		   || h->root.type == bfd_link_hash_defined
1022179407Sobrien		   || h->root.type == bfd_link_hash_defweak)
1023179407Sobrien	    {
1024179407Sobrien	      /* This is a relocation against a defined symbol.  The
1025179407Sobrien		 current addend in the instruction is simply the
1026179407Sobrien		 desired offset into the symbol (normally zero).  We
1027179407Sobrien		 are going to change this into a relocation against a
1028179407Sobrien		 defined symbol, so we want the instruction to hold
1029179407Sobrien		 the difference between the final definition of the
1030179407Sobrien		 symbol (which will end up in RELOCATION) and the GP
1031179407Sobrien		 value of OUTPUT_BFD (which is in GP).  */
1032179407Sobrien	      addend = - gp;
1033179407Sobrien	    }
1034179407Sobrien	  else
1035179407Sobrien	    {
1036179407Sobrien	      /* This is a relocation against an undefined or common
1037179407Sobrien		 symbol.  The current addend in the instruction is
1038179407Sobrien		 simply the desired offset into the symbol (normally
1039179407Sobrien		 zero).  We are generating relocatable output, and we
1040179407Sobrien		 aren't going to define this symbol, so we just leave
1041179407Sobrien		 the instruction alone.  */
1042179407Sobrien	      addend = 0;
1043179407Sobrien	    }
1044179407Sobrien	}
1045179407Sobrien
1046179407Sobrien      if (info->relocatable)
1047179407Sobrien	{
1048179407Sobrien	  /* We are generating relocatable output, and must convert
1049179407Sobrien	     the existing reloc.  */
1050179407Sobrien	  if (int_rel.r_extern)
1051179407Sobrien	    {
1052179407Sobrien	      if ((h->root.type == bfd_link_hash_defined
1053179407Sobrien		   || h->root.type == bfd_link_hash_defweak)
1054179407Sobrien		  && ! bfd_is_abs_section (h->root.u.def.section))
1055179407Sobrien		{
1056179407Sobrien		  const char *name;
1057179407Sobrien
1058179407Sobrien		  /* This symbol is defined in the output.  Convert
1059179407Sobrien		     the reloc from being against the symbol to being
1060179407Sobrien		     against the section.  */
1061179407Sobrien
1062179407Sobrien		  /* Clear the r_extern bit.  */
1063179407Sobrien		  int_rel.r_extern = 0;
1064179407Sobrien
1065179407Sobrien		  /* Compute a new r_symndx value.  */
1066179407Sobrien		  s = h->root.u.def.section;
1067179407Sobrien		  name = bfd_get_section_name (output_bfd,
1068179407Sobrien					       s->output_section);
1069179407Sobrien
1070179407Sobrien		  int_rel.r_symndx = -1;
1071179407Sobrien		  switch (name[1])
1072179407Sobrien		    {
1073179407Sobrien		    case 'b':
1074179407Sobrien		      if (strcmp (name, ".bss") == 0)
1075179407Sobrien			int_rel.r_symndx = RELOC_SECTION_BSS;
1076179407Sobrien		      break;
1077179407Sobrien		    case 'd':
1078179407Sobrien		      if (strcmp (name, ".data") == 0)
1079179407Sobrien			int_rel.r_symndx = RELOC_SECTION_DATA;
1080179407Sobrien		      break;
1081179407Sobrien		    case 'f':
1082179407Sobrien		      if (strcmp (name, ".fini") == 0)
1083179407Sobrien			int_rel.r_symndx = RELOC_SECTION_FINI;
1084179407Sobrien		      break;
1085179407Sobrien		    case 'i':
1086179407Sobrien		      if (strcmp (name, ".init") == 0)
1087179407Sobrien			int_rel.r_symndx = RELOC_SECTION_INIT;
1088179407Sobrien		      break;
1089179407Sobrien		    case 'l':
1090179407Sobrien		      if (strcmp (name, ".lit8") == 0)
1091179407Sobrien			int_rel.r_symndx = RELOC_SECTION_LIT8;
1092179407Sobrien		      else if (strcmp (name, ".lit4") == 0)
1093179407Sobrien			int_rel.r_symndx = RELOC_SECTION_LIT4;
1094179407Sobrien		      break;
1095179407Sobrien		    case 'r':
1096179407Sobrien		      if (strcmp (name, ".rdata") == 0)
1097179407Sobrien			int_rel.r_symndx = RELOC_SECTION_RDATA;
1098179407Sobrien		      break;
1099179407Sobrien		    case 's':
1100179407Sobrien		      if (strcmp (name, ".sdata") == 0)
1101179407Sobrien			int_rel.r_symndx = RELOC_SECTION_SDATA;
1102179407Sobrien		      else if (strcmp (name, ".sbss") == 0)
1103179407Sobrien			int_rel.r_symndx = RELOC_SECTION_SBSS;
1104179407Sobrien		      break;
1105179407Sobrien		    case 't':
1106179407Sobrien		      if (strcmp (name, ".text") == 0)
1107179407Sobrien			int_rel.r_symndx = RELOC_SECTION_TEXT;
1108179407Sobrien		      break;
1109179407Sobrien		    }
1110179407Sobrien
1111179407Sobrien		  if (int_rel.r_symndx == -1)
1112179407Sobrien		    abort ();
1113179407Sobrien
1114179407Sobrien		  /* Add the section VMA and the symbol value.  */
1115179407Sobrien		  relocation = (h->root.u.def.value
1116179407Sobrien				+ s->output_section->vma
1117179407Sobrien				+ s->output_offset);
1118179407Sobrien
1119179407Sobrien		  /* For a PC relative relocation, the object file
1120179407Sobrien		     currently holds just the addend.  We must adjust
1121179407Sobrien		     by the address to get the right value.  */
1122179407Sobrien		  if (howto->pc_relative)
1123218822Sdim		    relocation -= int_rel.r_vaddr - input_section->vma;
1124179407Sobrien
1125179407Sobrien		  h = NULL;
1126179407Sobrien		}
1127179407Sobrien	      else
1128179407Sobrien		{
1129179407Sobrien		  /* Change the symndx value to the right one for the
1130179407Sobrien		     output BFD.  */
1131179407Sobrien		  int_rel.r_symndx = h->indx;
1132179407Sobrien		  if (int_rel.r_symndx == -1)
1133179407Sobrien		    {
1134179407Sobrien		      /* This symbol is not being written out.  */
1135179407Sobrien		      if (! ((*info->callbacks->unattached_reloc)
1136179407Sobrien			     (info, h->root.root.string, input_bfd,
1137179407Sobrien			      input_section,
1138179407Sobrien			      int_rel.r_vaddr - input_section->vma)))
1139179407Sobrien			return FALSE;
1140179407Sobrien		      int_rel.r_symndx = 0;
1141179407Sobrien		    }
1142179407Sobrien		  relocation = 0;
1143179407Sobrien		}
1144179407Sobrien	    }
1145179407Sobrien	  else
1146179407Sobrien	    {
1147179407Sobrien	      /* This is a relocation against a section.  Adjust the
1148179407Sobrien		 value by the amount the section moved.  */
1149179407Sobrien	      relocation = (s->output_section->vma
1150179407Sobrien			    + s->output_offset
1151179407Sobrien			    - s->vma);
1152179407Sobrien	    }
1153179407Sobrien
1154179407Sobrien	  relocation += addend;
1155179407Sobrien	  addend = 0;
1156179407Sobrien
1157179407Sobrien	  /* Adjust a PC relative relocation by removing the reference
1158179407Sobrien	     to the original address in the section and including the
1159218822Sdim	     reference to the new address.  */
1160218822Sdim	  if (howto->pc_relative)
1161179407Sobrien	    relocation -= (input_section->output_section->vma
1162179407Sobrien			   + input_section->output_offset
1163179407Sobrien			   - input_section->vma);
1164179407Sobrien
1165179407Sobrien	  /* Adjust the contents.  */
1166179407Sobrien	  if (relocation == 0)
1167179407Sobrien	    r = bfd_reloc_ok;
1168179407Sobrien	  else
1169179407Sobrien	    {
1170218822Sdim	      if (int_rel.r_type != MIPS_R_REFHI)
1171179407Sobrien		r = _bfd_relocate_contents (howto, input_bfd, relocation,
1172179407Sobrien					    (contents
1173179407Sobrien					     + int_rel.r_vaddr
1174179407Sobrien					     - input_section->vma));
1175179407Sobrien	      else
1176179407Sobrien		{
1177179407Sobrien		  mips_relocate_hi (&int_rel,
1178179407Sobrien				    use_lo ? &lo_int_rel : NULL,
1179179407Sobrien				    input_bfd, input_section, contents,
1180218822Sdim				    relocation);
1181179407Sobrien		  r = bfd_reloc_ok;
1182179407Sobrien		}
1183179407Sobrien	    }
1184179407Sobrien
1185179407Sobrien	  /* Adjust the reloc address.  */
1186179407Sobrien	  int_rel.r_vaddr += (input_section->output_section->vma
1187179407Sobrien			      + input_section->output_offset
1188179407Sobrien			      - input_section->vma);
1189179407Sobrien
1190179407Sobrien	  /* Save the changed reloc information.  */
1191179407Sobrien	  mips_ecoff_swap_reloc_out (input_bfd, &int_rel, (PTR) ext_rel);
1192179407Sobrien	}
1193179407Sobrien      else
1194179407Sobrien	{
1195179407Sobrien	  /* We are producing a final executable.  */
1196179407Sobrien	  if (int_rel.r_extern)
1197179407Sobrien	    {
1198179407Sobrien	      /* This is a reloc against a symbol.  */
1199179407Sobrien	      if (h->root.type == bfd_link_hash_defined
1200179407Sobrien		  || h->root.type == bfd_link_hash_defweak)
1201179407Sobrien		{
1202179407Sobrien		  asection *hsec;
1203179407Sobrien
1204179407Sobrien		  hsec = h->root.u.def.section;
1205179407Sobrien		  relocation = (h->root.u.def.value
1206179407Sobrien				+ hsec->output_section->vma
1207179407Sobrien				+ hsec->output_offset);
1208179407Sobrien		}
1209179407Sobrien	      else
1210179407Sobrien		{
1211179407Sobrien		  if (! ((*info->callbacks->undefined_symbol)
1212179407Sobrien			 (info, h->root.root.string, input_bfd,
1213179407Sobrien			  input_section,
1214179407Sobrien			  int_rel.r_vaddr - input_section->vma, TRUE)))
1215179407Sobrien		    return FALSE;
1216179407Sobrien		  relocation = 0;
1217179407Sobrien		}
1218179407Sobrien	    }
1219179407Sobrien	  else
1220179407Sobrien	    {
1221179407Sobrien	      /* This is a reloc against a section.  */
1222179407Sobrien	      relocation = (s->output_section->vma
1223179407Sobrien			    + s->output_offset
1224179407Sobrien			    - s->vma);
1225179407Sobrien
1226179407Sobrien	      /* A PC relative reloc is already correct in the object
1227179407Sobrien		 file.  Make it look like a pcrel_offset relocation by
1228179407Sobrien		 adding in the start address.  */
1229179407Sobrien	      if (howto->pc_relative)
1230218822Sdim		relocation += int_rel.r_vaddr;
1231179407Sobrien	    }
1232179407Sobrien
1233218822Sdim	  if (int_rel.r_type != MIPS_R_REFHI)
1234179407Sobrien	    r = _bfd_final_link_relocate (howto,
1235179407Sobrien					  input_bfd,
1236179407Sobrien					  input_section,
1237179407Sobrien					  contents,
1238179407Sobrien					  (int_rel.r_vaddr
1239218822Sdim					   - input_section->vma),
1240179407Sobrien					  relocation,
1241179407Sobrien					  addend);
1242179407Sobrien	  else
1243179407Sobrien	    {
1244179407Sobrien	      mips_relocate_hi (&int_rel,
1245179407Sobrien				use_lo ? &lo_int_rel : NULL,
1246218822Sdim				input_bfd, input_section, contents,
1247218822Sdim				relocation);
1248179407Sobrien	      r = bfd_reloc_ok;
1249179407Sobrien	    }
1250179407Sobrien	}
1251179407Sobrien
1252179407Sobrien      /* MIPS_R_JMPADDR requires peculiar overflow detection.  The
1253179407Sobrien	 instruction provides a 28 bit address (the two lower bits are
1254179407Sobrien	 implicit zeroes) which is combined with the upper four bits
1255179407Sobrien	 of the instruction address.  */
1256179407Sobrien      if (r == bfd_reloc_ok
1257179407Sobrien	  && int_rel.r_type == MIPS_R_JMPADDR
1258179407Sobrien	  && (((relocation
1259179407Sobrien		+ addend
1260179407Sobrien		+ (int_rel.r_extern ? 0 : s->vma))
1261179407Sobrien	       & 0xf0000000)
1262179407Sobrien	      != ((input_section->output_section->vma
1263179407Sobrien		   + input_section->output_offset
1264218822Sdim		   + (int_rel.r_vaddr - input_section->vma))
1265179407Sobrien		  & 0xf0000000)))
1266179407Sobrien	r = bfd_reloc_overflow;
1267179407Sobrien
1268179407Sobrien      if (r != bfd_reloc_ok)
1269179407Sobrien	{
1270179407Sobrien	  switch (r)
1271179407Sobrien	    {
1272179407Sobrien	    default:
1273179407Sobrien	    case bfd_reloc_outofrange:
1274179407Sobrien	      abort ();
1275179407Sobrien	    case bfd_reloc_overflow:
1276179407Sobrien	      {
1277179407Sobrien		const char *name;
1278179407Sobrien
1279179407Sobrien		if (int_rel.r_extern)
1280218822Sdim		  name = NULL;
1281179407Sobrien		else
1282179407Sobrien		  name = bfd_section_name (input_bfd, s);
1283179407Sobrien		if (! ((*info->callbacks->reloc_overflow)
1284218822Sdim		       (info, (h ? &h->root : NULL), name, howto->name,
1285218822Sdim			(bfd_vma) 0, input_bfd, input_section,
1286179407Sobrien			int_rel.r_vaddr - input_section->vma)))
1287179407Sobrien		  return FALSE;
1288179407Sobrien	      }
1289179407Sobrien	      break;
1290179407Sobrien	    }
1291179407Sobrien	}
1292179407Sobrien    }
1293179407Sobrien
1294179407Sobrien  return TRUE;
1295179407Sobrien}
1296179407Sobrien
1297179407Sobrien/* This is the ECOFF backend structure.  The backend field of the
1298179407Sobrien   target vector points to this.  */
1299179407Sobrien
1300179407Sobrienstatic const struct ecoff_backend_data mips_ecoff_backend_data =
1301179407Sobrien{
1302179407Sobrien  /* COFF backend structure.  */
1303179407Sobrien  {
1304179407Sobrien    (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */
1305179407Sobrien    (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
1306179407Sobrien    (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */
1307179407Sobrien    (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/
1308179407Sobrien    (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */
1309179407Sobrien    (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */
1310179407Sobrien    (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
1311179407Sobrien    mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
1312179407Sobrien    mips_ecoff_swap_scnhdr_out,
1313179407Sobrien    FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, FALSE, 4, FALSE, 2,
1314179407Sobrien    mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
1315179407Sobrien    mips_ecoff_swap_scnhdr_in, NULL,
1316179407Sobrien    mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,
1317179407Sobrien    _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags,
1318179407Sobrien    _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table,
1319179407Sobrien    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1320179407Sobrien    NULL, NULL
1321179407Sobrien  },
1322179407Sobrien  /* Supported architecture.  */
1323179407Sobrien  bfd_arch_mips,
1324179407Sobrien  /* Initial portion of armap string.  */
1325179407Sobrien  "__________",
1326179407Sobrien  /* The page boundary used to align sections in a demand-paged
1327179407Sobrien     executable file.  E.g., 0x1000.  */
1328179407Sobrien  0x1000,
1329179407Sobrien  /* TRUE if the .rdata section is part of the text segment, as on the
1330179407Sobrien     Alpha.  FALSE if .rdata is part of the data segment, as on the
1331179407Sobrien     MIPS.  */
1332179407Sobrien  FALSE,
1333179407Sobrien  /* Bitsize of constructor entries.  */
1334179407Sobrien  32,
1335179407Sobrien  /* Reloc to use for constructor entries.  */
1336179407Sobrien  &mips_howto_table[MIPS_R_REFWORD],
1337179407Sobrien  {
1338179407Sobrien    /* Symbol table magic number.  */
1339179407Sobrien    magicSym,
1340179407Sobrien    /* Alignment of debugging information.  E.g., 4.  */
1341179407Sobrien    4,
1342179407Sobrien    /* Sizes of external symbolic information.  */
1343179407Sobrien    sizeof (struct hdr_ext),
1344179407Sobrien    sizeof (struct dnr_ext),
1345179407Sobrien    sizeof (struct pdr_ext),
1346179407Sobrien    sizeof (struct sym_ext),
1347179407Sobrien    sizeof (struct opt_ext),
1348179407Sobrien    sizeof (struct fdr_ext),
1349179407Sobrien    sizeof (struct rfd_ext),
1350179407Sobrien    sizeof (struct ext_ext),
1351179407Sobrien    /* Functions to swap in external symbolic data.  */
1352179407Sobrien    ecoff_swap_hdr_in,
1353179407Sobrien    ecoff_swap_dnr_in,
1354179407Sobrien    ecoff_swap_pdr_in,
1355179407Sobrien    ecoff_swap_sym_in,
1356179407Sobrien    ecoff_swap_opt_in,
1357179407Sobrien    ecoff_swap_fdr_in,
1358179407Sobrien    ecoff_swap_rfd_in,
1359179407Sobrien    ecoff_swap_ext_in,
1360179407Sobrien    _bfd_ecoff_swap_tir_in,
1361179407Sobrien    _bfd_ecoff_swap_rndx_in,
1362179407Sobrien    /* Functions to swap out external symbolic data.  */
1363179407Sobrien    ecoff_swap_hdr_out,
1364179407Sobrien    ecoff_swap_dnr_out,
1365179407Sobrien    ecoff_swap_pdr_out,
1366179407Sobrien    ecoff_swap_sym_out,
1367179407Sobrien    ecoff_swap_opt_out,
1368179407Sobrien    ecoff_swap_fdr_out,
1369179407Sobrien    ecoff_swap_rfd_out,
1370179407Sobrien    ecoff_swap_ext_out,
1371179407Sobrien    _bfd_ecoff_swap_tir_out,
1372179407Sobrien    _bfd_ecoff_swap_rndx_out,
1373179407Sobrien    /* Function to read in symbolic data.  */
1374179407Sobrien    _bfd_ecoff_slurp_symbolic_info
1375179407Sobrien  },
1376179407Sobrien  /* External reloc size.  */
1377179407Sobrien  RELSZ,
1378179407Sobrien  /* Reloc swapping functions.  */
1379179407Sobrien  mips_ecoff_swap_reloc_in,
1380179407Sobrien  mips_ecoff_swap_reloc_out,
1381179407Sobrien  /* Backend reloc tweaking.  */
1382179407Sobrien  mips_adjust_reloc_in,
1383179407Sobrien  mips_adjust_reloc_out,
1384179407Sobrien  /* Relocate section contents while linking.  */
1385179407Sobrien  mips_relocate_section,
1386179407Sobrien  /* Do final adjustments to filehdr and aouthdr.  */
1387179407Sobrien  NULL,
1388179407Sobrien  /* Read an element from an archive at a given file position.  */
1389179407Sobrien  _bfd_get_elt_at_filepos
1390179407Sobrien};
1391179407Sobrien
1392179407Sobrien/* Looking up a reloc type is MIPS specific.  */
1393179407Sobrien#define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup
1394218822Sdim#define _bfd_ecoff_bfd_reloc_name_lookup mips_bfd_reloc_name_lookup
1395179407Sobrien
1396179407Sobrien/* Getting relocated section contents is generic.  */
1397179407Sobrien#define _bfd_ecoff_bfd_get_relocated_section_contents \
1398179407Sobrien  bfd_generic_get_relocated_section_contents
1399179407Sobrien
1400179407Sobrien/* Handling file windows is generic.  */
1401179407Sobrien#define _bfd_ecoff_get_section_contents_in_window \
1402179407Sobrien  _bfd_generic_get_section_contents_in_window
1403179407Sobrien
1404179407Sobrien/* Relaxing sections is MIPS specific.  */
1405218822Sdim#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section
1406179407Sobrien
1407179407Sobrien/* GC of sections is not done.  */
1408179407Sobrien#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
1409179407Sobrien
1410179407Sobrien/* Merging of sections is not done.  */
1411179407Sobrien#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
1412179407Sobrien
1413218822Sdim#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
1414179407Sobrien#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
1415218822Sdim#define _bfd_ecoff_section_already_linked \
1416218822Sdim  _bfd_generic_section_already_linked
1417179407Sobrien
1418179407Sobrienextern const bfd_target ecoff_big_vec;
1419179407Sobrien
1420179407Sobrienconst bfd_target ecoff_little_vec =
1421179407Sobrien{
1422179407Sobrien  "ecoff-littlemips",		/* name */
1423179407Sobrien  bfd_target_ecoff_flavour,
1424179407Sobrien  BFD_ENDIAN_LITTLE,		/* data byte order is little */
1425179407Sobrien  BFD_ENDIAN_LITTLE,		/* header byte order is little */
1426179407Sobrien
1427179407Sobrien  (HAS_RELOC | EXEC_P |		/* object flags */
1428179407Sobrien   HAS_LINENO | HAS_DEBUG |
1429179407Sobrien   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
1430179407Sobrien
1431179407Sobrien  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
1432179407Sobrien  0,				/* leading underscore */
1433179407Sobrien  ' ',				/* ar_pad_char */
1434179407Sobrien  15,				/* ar_max_namelen */
1435179407Sobrien  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1436179407Sobrien     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1437179407Sobrien     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
1438179407Sobrien  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1439179407Sobrien     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1440179407Sobrien     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
1441179407Sobrien
1442179407Sobrien  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
1443179407Sobrien     _bfd_ecoff_archive_p, _bfd_dummy_target},
1444179407Sobrien  {bfd_false, _bfd_ecoff_mkobject,  /* bfd_set_format */
1445179407Sobrien     _bfd_generic_mkarchive, bfd_false},
1446179407Sobrien  {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
1447179407Sobrien     _bfd_write_archive_contents, bfd_false},
1448179407Sobrien
1449179407Sobrien     BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
1450179407Sobrien     BFD_JUMP_TABLE_COPY (_bfd_ecoff),
1451179407Sobrien     BFD_JUMP_TABLE_CORE (_bfd_nocore),
1452179407Sobrien     BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
1453179407Sobrien     BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
1454179407Sobrien     BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
1455179407Sobrien     BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
1456179407Sobrien     BFD_JUMP_TABLE_LINK (_bfd_ecoff),
1457179407Sobrien     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1458179407Sobrien
1459179407Sobrien  & ecoff_big_vec,
1460179407Sobrien
1461179407Sobrien  (PTR) &mips_ecoff_backend_data
1462179407Sobrien};
1463179407Sobrien
1464179407Sobrienconst bfd_target ecoff_big_vec =
1465179407Sobrien{
1466179407Sobrien  "ecoff-bigmips",		/* name */
1467179407Sobrien  bfd_target_ecoff_flavour,
1468179407Sobrien  BFD_ENDIAN_BIG,		/* data byte order is big */
1469179407Sobrien  BFD_ENDIAN_BIG,		/* header byte order is big */
1470179407Sobrien
1471179407Sobrien  (HAS_RELOC | EXEC_P |		/* object flags */
1472179407Sobrien   HAS_LINENO | HAS_DEBUG |
1473179407Sobrien   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
1474179407Sobrien
1475179407Sobrien  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
1476179407Sobrien  0,				/* leading underscore */
1477179407Sobrien  ' ',				/* ar_pad_char */
1478179407Sobrien  15,				/* ar_max_namelen */
1479179407Sobrien  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1480179407Sobrien     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1481179407Sobrien     bfd_getb16, bfd_getb_signed_16, bfd_putb16,
1482179407Sobrien  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1483179407Sobrien     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1484179407Sobrien     bfd_getb16, bfd_getb_signed_16, bfd_putb16,
1485179407Sobrien {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
1486179407Sobrien    _bfd_ecoff_archive_p, _bfd_dummy_target},
1487179407Sobrien {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */
1488179407Sobrien    _bfd_generic_mkarchive, bfd_false},
1489179407Sobrien {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
1490179407Sobrien    _bfd_write_archive_contents, bfd_false},
1491179407Sobrien
1492179407Sobrien     BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
1493179407Sobrien     BFD_JUMP_TABLE_COPY (_bfd_ecoff),
1494179407Sobrien     BFD_JUMP_TABLE_CORE (_bfd_nocore),
1495179407Sobrien     BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
1496179407Sobrien     BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
1497179407Sobrien     BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
1498179407Sobrien     BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
1499179407Sobrien     BFD_JUMP_TABLE_LINK (_bfd_ecoff),
1500179407Sobrien     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1501179407Sobrien
1502179407Sobrien  & ecoff_little_vec,
1503179407Sobrien
1504179407Sobrien  (PTR) &mips_ecoff_backend_data
1505179407Sobrien};
1506179407Sobrien
1507179407Sobrienconst bfd_target ecoff_biglittle_vec =
1508179407Sobrien{
1509179407Sobrien  "ecoff-biglittlemips",		/* name */
1510179407Sobrien  bfd_target_ecoff_flavour,
1511179407Sobrien  BFD_ENDIAN_LITTLE,		/* data byte order is little */
1512179407Sobrien  BFD_ENDIAN_BIG,		/* header byte order is big */
1513179407Sobrien
1514179407Sobrien  (HAS_RELOC | EXEC_P |		/* object flags */
1515179407Sobrien   HAS_LINENO | HAS_DEBUG |
1516179407Sobrien   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
1517179407Sobrien
1518179407Sobrien  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
1519179407Sobrien  0,				/* leading underscore */
1520179407Sobrien  ' ',				/* ar_pad_char */
1521179407Sobrien  15,				/* ar_max_namelen */
1522179407Sobrien  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1523179407Sobrien     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1524179407Sobrien     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
1525179407Sobrien  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1526179407Sobrien     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1527179407Sobrien     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
1528179407Sobrien
1529179407Sobrien  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
1530179407Sobrien     _bfd_ecoff_archive_p, _bfd_dummy_target},
1531179407Sobrien  {bfd_false, _bfd_ecoff_mkobject,  /* bfd_set_format */
1532179407Sobrien     _bfd_generic_mkarchive, bfd_false},
1533179407Sobrien  {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
1534179407Sobrien     _bfd_write_archive_contents, bfd_false},
1535179407Sobrien
1536179407Sobrien     BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
1537179407Sobrien     BFD_JUMP_TABLE_COPY (_bfd_ecoff),
1538179407Sobrien     BFD_JUMP_TABLE_CORE (_bfd_nocore),
1539179407Sobrien     BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
1540179407Sobrien     BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
1541179407Sobrien     BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
1542179407Sobrien     BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
1543179407Sobrien     BFD_JUMP_TABLE_LINK (_bfd_ecoff),
1544179407Sobrien     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1545179407Sobrien
1546179407Sobrien  NULL,
1547179407Sobrien
1548179407Sobrien  (PTR) &mips_ecoff_backend_data
1549179407Sobrien};
1550