* coff-alpha.c: Implemented reloc handling for the linker, made
[platform/upstream/binutils.git] / bfd / coff-mips.c
1 /* BFD back-end for MIPS Extended-Coff files.
2    Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3    Original version by Per Bothner.
4    Full support added by Ian Lance Taylor, ian@cygnus.com.
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
25 #include "seclet.h"
26 #include "coff/internal.h"
27 #include "coff/sym.h"
28 #include "coff/symconst.h"
29 #include "coff/ecoff.h"
30 #include "coff/mips.h"
31 #include "libcoff.h"
32 #include "libecoff.h"
33 \f
34 /* Prototypes for static functions.  */
35
36 static boolean mips_ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr));
37 static void mips_ecoff_swap_reloc_in PARAMS ((bfd *, PTR,
38                                               struct internal_reloc *));
39 static void mips_ecoff_swap_reloc_out PARAMS ((bfd *,
40                                                const struct internal_reloc *,
41                                                PTR));
42 static void mips_adjust_reloc_in PARAMS ((bfd *,
43                                           const struct internal_reloc *,
44                                           arelent *));
45 static void mips_adjust_reloc_out PARAMS ((bfd *, const arelent *,
46                                            struct internal_reloc *));
47 static bfd_reloc_status_type mips_generic_reloc PARAMS ((bfd *abfd,
48                                                          arelent *reloc,
49                                                          asymbol *symbol,
50                                                          PTR data,
51                                                          asection *section,
52                                                          bfd *output_bfd));
53 static bfd_reloc_status_type mips_refhi_reloc PARAMS ((bfd *abfd,
54                                                        arelent *reloc,
55                                                        asymbol *symbol,
56                                                        PTR data,
57                                                        asection *section,
58                                                        bfd *output_bfd));
59 static bfd_reloc_status_type mips_reflo_reloc PARAMS ((bfd *abfd,
60                                                        arelent *reloc,
61                                                        asymbol *symbol,
62                                                        PTR data,
63                                                        asection *section,
64                                                        bfd *output_bfd));
65 static bfd_reloc_status_type mips_gprel_reloc PARAMS ((bfd *abfd,
66                                                        arelent *reloc,
67                                                        asymbol *symbol,
68                                                        PTR data,
69                                                        asection *section,
70                                                        bfd *output_bfd));
71 \f
72 /* ECOFF has COFF sections, but the debugging information is stored in
73    a completely different format.  ECOFF targets use some of the
74    swapping routines from coffswap.h, and some of the generic COFF
75    routines in coffgen.c, but, unlike the real COFF targets, do not
76    use coffcode.h itself.
77
78    Get the generic COFF swapping routines, except for the reloc,
79    symbol, and lineno ones.  Give them ECOFF names.  */
80 #define MIPSECOFF
81 #define NO_COFF_RELOCS
82 #define NO_COFF_SYMBOLS
83 #define NO_COFF_LINENOS
84 #define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in
85 #define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out
86 #define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in
87 #define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out
88 #define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in
89 #define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out
90 #include "coffswap.h"
91
92 /* Get the ECOFF swapping routines.  */
93 #define ECOFF_32
94 #include "ecoffswap.h"
95 \f
96 /* How to process the various relocs types.  */
97
98 static reloc_howto_type mips_howto_table[] =
99 {
100   /* Reloc type 0 is ignored.  The reloc reading code ensures that
101      this is a reference to the .abs section, which will cause
102      bfd_perform_relocation to do nothing.  */
103   HOWTO (MIPS_R_IGNORE, /* type */
104          0,                     /* rightshift */
105          0,                     /* size (0 = byte, 1 = short, 2 = long) */
106          8,                     /* bitsize */
107          false,                 /* pc_relative */
108          0,                     /* bitpos */
109          complain_overflow_dont, /* complain_on_overflow */
110          0,                     /* special_function */
111          "IGNORE",              /* name */
112          false,                 /* partial_inplace */
113          0,                     /* src_mask */
114          0,                     /* dst_mask */
115          false),                /* pcrel_offset */
116
117   /* A 16 bit reference to a symbol, normally from a data section.  */
118   HOWTO (MIPS_R_REFHALF,        /* type */
119          0,                     /* rightshift */
120          1,                     /* size (0 = byte, 1 = short, 2 = long) */
121          16,                    /* bitsize */
122          false,                 /* pc_relative */
123          0,                     /* bitpos */
124          complain_overflow_bitfield, /* complain_on_overflow */
125          mips_generic_reloc,    /* special_function */
126          "REFHALF",             /* name */
127          true,                  /* partial_inplace */
128          0xffff,                /* src_mask */
129          0xffff,                /* dst_mask */
130          false),                /* pcrel_offset */
131
132   /* A 32 bit reference to a symbol, normally from a data section.  */
133   HOWTO (MIPS_R_REFWORD,        /* type */
134          0,                     /* rightshift */
135          2,                     /* size (0 = byte, 1 = short, 2 = long) */
136          32,                    /* bitsize */
137          false,                 /* pc_relative */
138          0,                     /* bitpos */
139          complain_overflow_bitfield, /* complain_on_overflow */
140          mips_generic_reloc,    /* special_function */
141          "REFWORD",             /* name */
142          true,                  /* partial_inplace */
143          0xffffffff,            /* src_mask */
144          0xffffffff,            /* dst_mask */
145          false),                /* pcrel_offset */
146
147   /* A 26 bit absolute jump address.  */
148   HOWTO (MIPS_R_JMPADDR,        /* type */
149          2,                     /* rightshift */
150          2,                     /* size (0 = byte, 1 = short, 2 = long) */
151          26,                    /* bitsize */
152          false,                 /* pc_relative */
153          0,                     /* bitpos */
154          complain_overflow_dont, /* complain_on_overflow */
155                                 /* This needs complex overflow
156                                    detection, because the upper four
157                                    bits must match the PC.  */
158          mips_generic_reloc,    /* special_function */
159          "JMPADDR",             /* name */
160          true,                  /* partial_inplace */
161          0x3ffffff,             /* src_mask */
162          0x3ffffff,             /* dst_mask */
163          false),                /* pcrel_offset */
164
165   /* The high 16 bits of a symbol value.  Handled by the function
166      mips_refhi_reloc.  */
167   HOWTO (MIPS_R_REFHI,          /* type */
168          16,                    /* rightshift */
169          2,                     /* size (0 = byte, 1 = short, 2 = long) */
170          16,                    /* bitsize */
171          false,                 /* pc_relative */
172          0,                     /* bitpos */
173          complain_overflow_bitfield, /* complain_on_overflow */
174          mips_refhi_reloc,      /* special_function */
175          "REFHI",               /* name */
176          true,                  /* partial_inplace */
177          0xffff,                /* src_mask */
178          0xffff,                /* dst_mask */
179          false),                /* pcrel_offset */
180
181   /* The low 16 bits of a symbol value.  */
182   HOWTO (MIPS_R_REFLO,          /* type */
183          0,                     /* rightshift */
184          2,                     /* size (0 = byte, 1 = short, 2 = long) */
185          16,                    /* bitsize */
186          false,                 /* pc_relative */
187          0,                     /* bitpos */
188          complain_overflow_dont, /* complain_on_overflow */
189          mips_reflo_reloc,      /* special_function */
190          "REFLO",               /* name */
191          true,                  /* partial_inplace */
192          0xffff,                /* src_mask */
193          0xffff,                /* dst_mask */
194          false),                /* pcrel_offset */
195
196   /* A reference to an offset from the gp register.  Handled by the
197      function mips_gprel_reloc.  */
198   HOWTO (MIPS_R_GPREL,          /* type */
199          0,                     /* rightshift */
200          2,                     /* size (0 = byte, 1 = short, 2 = long) */
201          16,                    /* bitsize */
202          false,                 /* pc_relative */
203          0,                     /* bitpos */
204          complain_overflow_signed, /* complain_on_overflow */
205          mips_gprel_reloc,      /* special_function */
206          "GPREL",               /* name */
207          true,                  /* partial_inplace */
208          0xffff,                /* src_mask */
209          0xffff,                /* dst_mask */
210          false),                /* pcrel_offset */
211
212   /* A reference to a literal using an offset from the gp register.
213      Handled by the function mips_gprel_reloc.  */
214   HOWTO (MIPS_R_LITERAL,        /* type */
215          0,                     /* rightshift */
216          2,                     /* size (0 = byte, 1 = short, 2 = long) */
217          16,                    /* bitsize */
218          false,                 /* pc_relative */
219          0,                     /* bitpos */
220          complain_overflow_signed, /* complain_on_overflow */
221          mips_gprel_reloc,      /* special_function */
222          "LITERAL",             /* name */
223          true,                  /* partial_inplace */
224          0xffff,                /* src_mask */
225          0xffff,                /* dst_mask */
226          false)                 /* pcrel_offset */
227 };
228
229 #define MIPS_HOWTO_COUNT \
230   (sizeof mips_howto_table / sizeof mips_howto_table[0])
231 \f
232 /* See whether the magic number matches.  */
233
234 static boolean
235 mips_ecoff_bad_format_hook (abfd, filehdr)
236      bfd *abfd;
237      PTR filehdr;
238 {
239   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
240
241   switch (internal_f->f_magic)
242     {
243     case MIPS_MAGIC_1:
244       /* I don't know what endianness this implies.  */
245       return true;
246
247     case MIPS_MAGIC_BIG:
248     case MIPS_MAGIC_BIG2:
249     case MIPS_MAGIC_BIG3:
250       return abfd->xvec->byteorder_big_p;
251
252     case MIPS_MAGIC_LITTLE:
253     case MIPS_MAGIC_LITTLE2:
254     case MIPS_MAGIC_LITTLE3:
255       return abfd->xvec->byteorder_big_p == false;
256
257     default:
258       return false;
259     }
260 }
261 \f
262 /* Reloc handling.  MIPS ECOFF relocs are packed into 8 bytes in
263    external form.  They use a bit which indicates whether the symbol
264    is external.  */
265
266 /* Swap a reloc in.  */
267
268 static void
269 mips_ecoff_swap_reloc_in (abfd, ext_ptr, intern)
270      bfd *abfd;
271      PTR ext_ptr;
272      struct internal_reloc *intern;
273 {
274   const RELOC *ext = (RELOC *) ext_ptr;
275
276   intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
277   if (abfd->xvec->header_byteorder_big_p != false)
278     {
279       intern->r_symndx = (((int) ext->r_bits[0]
280                            << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
281                           | ((int) ext->r_bits[1]
282                              << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
283                           | ((int) ext->r_bits[2]
284                              << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
285       intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
286                         >> RELOC_BITS3_TYPE_SH_BIG);
287       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
288     }
289   else
290     {
291       intern->r_symndx = (((int) ext->r_bits[0]
292                            << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
293                           | ((int) ext->r_bits[1]
294                              << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
295                           | ((int) ext->r_bits[2]
296                              << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
297       intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
298                         >> RELOC_BITS3_TYPE_SH_LITTLE);
299       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
300     }
301 }
302
303 /* Swap a reloc out.  */
304
305 static void
306 mips_ecoff_swap_reloc_out (abfd, intern, dst)
307      bfd *abfd;
308      const struct internal_reloc *intern;
309      PTR dst;
310 {
311   RELOC *ext = (RELOC *) dst;
312
313   BFD_ASSERT (intern->r_extern
314               || (intern->r_symndx >= 0 && intern->r_symndx <= 12));
315
316   bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
317   if (abfd->xvec->header_byteorder_big_p != false)
318     {
319       ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
320       ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
321       ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
322       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
323                          & RELOC_BITS3_TYPE_BIG)
324                         | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
325     }
326   else
327     {
328       ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
329       ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
330       ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
331       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
332                          & RELOC_BITS3_TYPE_LITTLE)
333                         | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
334     }
335 }
336
337 /* Finish canonicalizing a reloc.  Part of this is generic to all
338    ECOFF targets, and that part is in ecoff.c.  The rest is done in
339    this backend routine.  It must fill in the howto field.  */
340
341 static void
342 mips_adjust_reloc_in (abfd, intern, rptr)
343      bfd *abfd;
344      const struct internal_reloc *intern;
345      arelent *rptr;
346 {
347   if (intern->r_type > MIPS_R_LITERAL)
348     abort ();
349
350   if (! intern->r_extern
351       && (intern->r_type == MIPS_R_GPREL
352           || intern->r_type == MIPS_R_LITERAL))
353     rptr->addend += ecoff_data (abfd)->gp;
354
355   /* If the type is MIPS_R_IGNORE, make sure this is a reference to
356      the absolute section so that the reloc is ignored.  */
357   if (intern->r_type == MIPS_R_IGNORE)
358     rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
359
360   rptr->howto = &mips_howto_table[intern->r_type];
361 }
362
363 /* Make any adjustments needed to a reloc before writing it out.  None
364    are needed for MIPS.  */
365
366 static void
367 mips_adjust_reloc_in (abfd, rel, intern)
368      bfd *abfd;
369      const arelent *rel;
370      struct internal_reloc *intern;
371 {
372 }
373
374 /* ECOFF relocs are either against external symbols, or against
375    sections.  If we are producing relocateable output, and the reloc
376    is against an external symbol, and nothing has given us any
377    additional addend, the resulting reloc will also be against the
378    same symbol.  In such a case, we don't want to change anything
379    about the way the reloc is handled, since it will all be done at
380    final link time.  Rather than put special case code into
381    bfd_perform_relocation, all the reloc types use this howto
382    function.  It just short circuits the reloc if producing
383    relocateable output against an external symbol.  */
384
385 static bfd_reloc_status_type
386 mips_generic_reloc (abfd,
387                     reloc_entry,
388                     symbol,
389                     data,
390                     input_section,
391                     output_bfd)
392      bfd *abfd;
393      arelent *reloc_entry;
394      asymbol *symbol;
395      PTR data;
396      asection *input_section;
397      bfd *output_bfd;
398 {
399   if (output_bfd != (bfd *) NULL
400       && (symbol->flags & BSF_SECTION_SYM) == 0
401       && reloc_entry->addend == 0)
402     {
403       reloc_entry->address += input_section->output_offset;
404       return bfd_reloc_ok;
405     }
406
407   return bfd_reloc_continue;
408 }
409
410 /* Do a REFHI relocation.  This has to be done in combination with a
411    REFLO reloc, because there is a carry from the REFLO to the REFHI.
412    Here we just save the information we need; we do the actual
413    relocation when we see the REFLO.  MIPS ECOFF requires that the
414    REFLO immediately follow the REFHI, so this ought to work.  */
415
416 static bfd_byte *mips_refhi_addr;
417 static bfd_vma mips_refhi_addend;
418
419 static bfd_reloc_status_type
420 mips_refhi_reloc (abfd,
421                   reloc_entry,
422                   symbol,
423                   data,
424                   input_section,
425                   output_bfd)
426      bfd *abfd;
427      arelent *reloc_entry;
428      asymbol *symbol;
429      PTR data;
430      asection *input_section;
431      bfd *output_bfd;
432 {
433   bfd_reloc_status_type ret;
434   bfd_vma relocation;
435
436   /* If we're relocating, and this an external symbol, we don't want
437      to change anything.  */
438   if (output_bfd != (bfd *) NULL
439       && (symbol->flags & BSF_SECTION_SYM) == 0
440       && reloc_entry->addend == 0)
441     {
442       reloc_entry->address += input_section->output_offset;
443       return bfd_reloc_ok;
444     }
445
446   ret = bfd_reloc_ok;
447   if (symbol->section == &bfd_und_section
448       && output_bfd == (bfd *) NULL)
449     ret = bfd_reloc_undefined;
450
451   if (bfd_is_com_section (symbol->section))
452     relocation = 0;
453   else
454     relocation = symbol->value;
455
456   relocation += symbol->section->output_section->vma;
457   relocation += symbol->section->output_offset;
458   relocation += reloc_entry->addend;
459
460   if (reloc_entry->address > input_section->_cooked_size)
461     return bfd_reloc_outofrange;
462
463   /* Save the information, and let REFLO do the actual relocation.  */
464   mips_refhi_addr = (bfd_byte *) data + reloc_entry->address;
465   mips_refhi_addend = relocation;
466
467   if (output_bfd != (bfd *) NULL)
468     reloc_entry->address += input_section->output_offset;
469
470   return ret;
471 }
472
473 /* Do a REFLO relocation.  This is a straightforward 16 bit inplace
474    relocation; this function exists in order to do the REFHI
475    relocation described above.  */
476
477 static bfd_reloc_status_type
478 mips_reflo_reloc (abfd,
479                   reloc_entry,
480                   symbol,
481                   data,
482                   input_section,
483                   output_bfd)
484      bfd *abfd;
485      arelent *reloc_entry;
486      asymbol *symbol;
487      PTR data;
488      asection *input_section;
489      bfd *output_bfd;
490 {
491   if (mips_refhi_addr != (bfd_byte *) NULL)
492     {
493       unsigned long insn;
494       unsigned long val;
495       unsigned long vallo;
496
497       /* Do the REFHI relocation.  Note that we actually don't need to
498          know anything about the REFLO itself, except where to find
499          the low 16 bits of the addend needed by the REFHI.  */
500       insn = bfd_get_32 (abfd, mips_refhi_addr);
501       vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
502                & 0xffff);
503       val = ((insn & 0xffff) << 16) + vallo;
504       val += mips_refhi_addend;
505
506       /* The low order 16 bits are always treated as a signed value.
507          Therefore, a negative value in the low order bits requires an
508          adjustment in the high order bits.  We need to make this
509          adjustment in two ways: once for the bits we took from the
510          data, and once for the bits we are putting back in to the
511          data.  */
512       if ((vallo & 0x8000) != 0)
513         val -= 0x10000;
514       if ((val & 0x8000) != 0)
515         val += 0x10000;
516
517       insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
518       bfd_put_32 (abfd, insn, mips_refhi_addr);
519
520       mips_refhi_addr = (bfd_byte *) NULL;
521     }
522
523   /* Now do the REFLO reloc in the usual way.  */
524   return mips_generic_reloc (abfd, reloc_entry, symbol, data,
525                               input_section, output_bfd);
526 }
527
528 /* Do a GPREL relocation.  This is a 16 bit value which must become
529    the offset from the gp register.  */
530
531 static bfd_reloc_status_type
532 mips_gprel_reloc (abfd,
533                    reloc_entry,
534                    symbol,
535                    data,
536                    input_section,
537                    output_bfd)
538      bfd *abfd;
539      arelent *reloc_entry;
540      asymbol *symbol;
541      PTR data;
542      asection *input_section;
543      bfd *output_bfd;
544 {
545   boolean relocateable;
546   bfd_vma relocation;
547   unsigned long val;
548   unsigned long insn;
549
550   /* If we're relocating, and this is an external symbol with no
551      addend, we don't want to change anything.  We will only have an
552      addend if this is a newly created reloc, not read from an ECOFF
553      file.  */
554   if (output_bfd != (bfd *) NULL
555       && (symbol->flags & BSF_SECTION_SYM) == 0
556       && reloc_entry->addend == 0)
557     {
558       reloc_entry->address += input_section->output_offset;
559       return bfd_reloc_ok;
560     }
561
562   if (output_bfd != (bfd *) NULL)
563     relocateable = true;
564   else
565     {
566       relocateable = false;
567       output_bfd = symbol->section->output_section->owner;
568     }
569
570   if (symbol->section == &bfd_und_section
571       && relocateable == false)
572     return bfd_reloc_undefined;
573
574   /* We have to figure out the gp value, so that we can adjust the
575      symbol value correctly.  We look up the symbol _gp in the output
576      BFD.  If we can't find it, we're stuck.  We cache it in the ECOFF
577      target data.  We don't need to adjust the symbol value for an
578      external symbol if we are producing relocateable output.  */
579   if (ecoff_data (output_bfd)->gp == 0
580       && (relocateable == false
581           || (symbol->flags & BSF_SECTION_SYM) != 0))
582     {
583       if (relocateable != false)
584         {
585           /* Make up a value.  */
586           ecoff_data (output_bfd)->gp =
587             symbol->section->output_section->vma + 0x4000;
588         }
589       else
590         {
591           unsigned int count;
592           asymbol **sym;
593           unsigned int i;
594
595           count = bfd_get_symcount (output_bfd);
596           sym = bfd_get_outsymbols (output_bfd);
597
598           if (sym == (asymbol **) NULL)
599             i = count;
600           else
601             {
602               for (i = 0; i < count; i++, sym++)
603                 {
604                   register CONST char *name;
605
606                   name = bfd_asymbol_name (*sym);
607                   if (*name == '_' && strcmp (name, "_gp") == 0)
608                     {
609                       ecoff_data (output_bfd)->gp = bfd_asymbol_value (*sym);
610                       break;
611                     }
612                 }
613             }
614
615           if (i >= count)
616             {
617               /* Only get the error once.  */
618               ecoff_data (output_bfd)->gp = 4;
619               /* FIXME: How can we get the program name here?  */
620               fprintf (stderr,
621                        "GP relative relocation when _gp not defined\n");
622               return bfd_reloc_dangerous;
623             }
624         }
625     }
626
627   if (bfd_is_com_section (symbol->section))
628     relocation = 0;
629   else
630     relocation = symbol->value;
631
632   relocation += symbol->section->output_section->vma;
633   relocation += symbol->section->output_offset;
634
635   if (reloc_entry->address > input_section->_cooked_size)
636     return bfd_reloc_outofrange;
637
638   insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
639
640   /* Set val to the offset into the section or symbol.  */
641   val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
642   if (val & 0x8000)
643     val -= 0x10000;
644
645   /* Adjust val for the final section location and GP value.  If we
646      are producing relocateable output, we don't want to do this for
647      an external symbol.  */
648   if (relocateable == false
649       || (symbol->flags & BSF_SECTION_SYM) != 0)
650     val += relocation - ecoff_data (output_bfd)->gp;
651
652   insn = (insn &~ 0xffff) | (val & 0xffff);
653   bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
654
655   if (relocateable != false)
656     reloc_entry->address += input_section->output_offset;
657
658   /* Make sure it fit in 16 bits.  */
659   if (val >= 0x8000 && val < 0xffff8000)
660     return bfd_reloc_outofrange;
661
662   return bfd_reloc_ok;
663 }
664
665 /* Get the howto structure for a generic reloc type.  */
666
667 static CONST struct reloc_howto_struct *
668 mips_bfd_reloc_type_lookup (abfd, code)
669      bfd *abfd;
670      bfd_reloc_code_real_type code;
671 {
672   int mips_type;
673
674   switch (code)
675     {
676     case BFD_RELOC_16:
677       mips_type = MIPS_R_REFHALF;
678       break;
679     case BFD_RELOC_32:
680       mips_type = MIPS_R_REFWORD;
681       break;
682     case BFD_RELOC_MIPS_JMP:
683       mips_type = MIPS_R_JMPADDR;
684       break;
685     case BFD_RELOC_HI16_S:
686       mips_type = MIPS_R_REFHI;
687       break;
688     case BFD_RELOC_LO16:
689       mips_type = MIPS_R_REFLO;
690       break;
691     case BFD_RELOC_MIPS_GPREL:
692       mips_type = MIPS_R_GPREL;
693       break;
694     default:
695       return (CONST struct reloc_howto_struct *) NULL;
696     }
697
698   return &mips_howto_table[mips_type];
699 }
700 \f
701 #ifdef HOST_IRIX4
702
703 #include <core.out.h>
704
705 struct sgi_core_struct 
706 {
707   int sig;
708   char cmd[CORE_NAMESIZE];
709 };
710
711 #define core_hdr(bfd) ((bfd)->tdata.sgi_core_data)
712 #define core_signal(bfd) (core_hdr(bfd)->sig)
713 #define core_command(bfd) (core_hdr(bfd)->cmd)
714
715 static asection *
716 make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos)
717      bfd *abfd;
718      CONST char *name;
719      flagword flags;
720      bfd_size_type _raw_size;
721      bfd_vma vma;
722      file_ptr filepos;
723 {
724   asection *asect;
725
726   asect = bfd_make_section (abfd, name);
727   if (!asect)
728     return NULL;
729
730   asect->flags = flags;
731   asect->_raw_size = _raw_size;
732   asect->vma = vma;
733   asect->filepos = filepos;
734   asect->alignment_power = 4;
735
736   return asect;
737 }
738
739 static bfd_target *
740 ecoff_core_file_p (abfd)
741      bfd *abfd;
742 {
743   int val;
744   int i;
745   char *secname;
746   struct coreout coreout;
747   struct idesc *idg, *idf, *ids;
748
749   val = bfd_read ((PTR)&coreout, 1, sizeof coreout, abfd);
750   if (val != sizeof coreout)
751     return 0;
752
753   if (coreout.c_magic != CORE_MAGIC
754       || coreout.c_version != CORE_VERSION1)
755     return 0;
756
757   core_hdr (abfd) = (struct sgi_core_struct *) bfd_zalloc (abfd, sizeof (struct sgi_core_struct));
758   if (!core_hdr (abfd))
759     return NULL;
760
761   strncpy (core_command (abfd), coreout.c_name, CORE_NAMESIZE);
762   core_signal (abfd) = coreout.c_sigcause;
763
764   bfd_seek (abfd, coreout.c_vmapoffset, SEEK_SET);
765
766   for (i = 0; i < coreout.c_nvmap; i++)
767     {
768       struct vmap vmap;
769
770       val = bfd_read ((PTR)&vmap, 1, sizeof vmap, abfd);
771       if (val != sizeof vmap)
772         break;
773
774       switch (vmap.v_type)
775         {
776         case VDATA:
777           secname = ".data";
778           break;
779         case VSTACK:
780           secname = ".stack";
781           break;
782         default:
783           continue;
784         }
785
786       if (!make_bfd_asection (abfd, secname,
787                               SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS,
788                               vmap.v_len,
789                               vmap.v_vaddr,
790                               vmap.v_offset,
791                               2))
792         return NULL;
793     }
794
795   /* Make sure that the regs are contiguous within the core file. */
796
797   idg = &coreout.c_idesc[I_GPREGS];
798   idf = &coreout.c_idesc[I_FPREGS];
799   ids = &coreout.c_idesc[I_SPECREGS];
800
801   if (idg->i_offset + idg->i_len != idf->i_offset
802       || idf->i_offset + idf->i_len != ids->i_offset)
803     return 0;                   /* Can't deal with non-contig regs */
804
805   bfd_seek (abfd, idg->i_offset, SEEK_SET);
806
807   make_bfd_asection (abfd, ".reg",
808                      SEC_ALLOC+SEC_HAS_CONTENTS,
809                      idg->i_len + idf->i_len + ids->i_len,
810                      0,
811                      idg->i_offset);
812
813   /* OK, we believe you.  You're a core file (sure, sure).  */
814
815   return abfd->xvec;
816 }
817
818 static char *
819 ecoff_core_file_failing_command (abfd)
820      bfd *abfd;
821 {
822   return core_command (abfd);
823 }
824
825 static int
826 ecoff_core_file_failing_signal (abfd)
827      bfd *abfd;
828 {
829   return core_signal (abfd);
830 }
831
832 static boolean
833 ecoff_core_file_matches_executable_p (core_bfd, exec_bfd)
834      bfd *core_bfd, *exec_bfd;
835 {
836   return true;                  /* XXX - FIXME */
837 }
838 #else /* not def HOST_IRIX4 */
839 #define ecoff_core_file_p _bfd_dummy_target
840 #define ecoff_core_file_failing_command _bfd_dummy_core_file_failing_command
841 #define ecoff_core_file_failing_signal _bfd_dummy_core_file_failing_signal
842 #define ecoff_core_file_matches_executable_p \
843   _bfd_dummy_core_file_matches_executable_p
844 #endif
845 \f
846 /* This is the ECOFF backend structure.  The backend field of the
847    target vector points to this.  */
848
849 static const struct ecoff_backend_data mips_ecoff_backend_data =
850 {
851   /* COFF backend structure.  */
852   {
853     (void (*) PARAMS ((bfd *,PTR,int,int,PTR))) bfd_void, /* aux_in */
854     (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
855     (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */
856     (unsigned (*) PARAMS ((bfd *,PTR,int,int,PTR))) bfd_void, /* aux_out */
857     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */
858     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */
859     (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
860     mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
861     mips_ecoff_swap_scnhdr_out,
862     FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, true,
863     mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
864     mips_ecoff_swap_scnhdr_in, mips_ecoff_bad_format_hook,
865     ecoff_set_arch_mach_hook, ecoff_mkobject_hook,
866     ecoff_styp_to_sec_flags, ecoff_make_section_hook, ecoff_set_alignment_hook,
867     ecoff_slurp_symbol_table, NULL, NULL
868   },
869   /* Supported architecture.  */
870   bfd_arch_mips,
871   /* Symbol table magic number.  */
872   magicSym,
873   /* Initial portion of armap string.  */
874   "__________",
875   /* Alignment of debugging information.  E.g., 4.  */
876   4,
877   /* The page boundary used to align sections in a demand-paged
878      executable file.  E.g., 0x1000.  */
879   0x1000,
880   /* True if the .rdata section is part of the text segment, as on the
881      Alpha.  False if .rdata is part of the data segment, as on the
882      MIPS.  */
883   false,
884   /* Bitsize of constructor entries.  */
885   32,
886   /* Reloc to use for constructor entries.  */
887   &mips_howto_table[MIPS_R_REFWORD],
888   /* Sizes of external symbolic information.  */
889   sizeof (struct hdr_ext),
890   sizeof (struct dnr_ext),
891   sizeof (struct pdr_ext),
892   sizeof (struct sym_ext),
893   sizeof (struct opt_ext),
894   sizeof (struct fdr_ext),
895   sizeof (struct rfd_ext),
896   sizeof (struct ext_ext),
897   /* Functions to swap in external symbolic data.  */
898   ecoff_swap_hdr_in,
899   ecoff_swap_dnr_in,
900   ecoff_swap_pdr_in,
901   ecoff_swap_sym_in,
902   ecoff_swap_opt_in,
903   ecoff_swap_fdr_in,
904   ecoff_swap_rfd_in,
905   ecoff_swap_ext_in,
906   /* Functions to swap out external symbolic data.  */
907   ecoff_swap_hdr_out,
908   ecoff_swap_dnr_out,
909   ecoff_swap_pdr_out,
910   ecoff_swap_sym_out,
911   ecoff_swap_opt_out,
912   ecoff_swap_fdr_out,
913   ecoff_swap_rfd_out,
914   ecoff_swap_ext_out,
915   /* External reloc size.  */
916   RELSZ,
917   /* Reloc swapping functions.  */
918   mips_ecoff_swap_reloc_in,
919   mips_ecoff_swap_reloc_out,
920   /* Backend reloc tweaking.  */
921   mips_adjust_reloc_in,
922   mips_adjust_reloc_out
923 };
924
925 /* Looking up a reloc type is MIPS specific.  */
926 #define ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup
927
928 /* Getting relocated section contents is generic.  */
929 #define ecoff_bfd_get_relocated_section_contents \
930   bfd_generic_get_relocated_section_contents
931
932 bfd_target ecoff_little_vec =
933 {
934   "ecoff-littlemips",           /* name */
935   bfd_target_ecoff_flavour,
936   false,                        /* data byte order is little */
937   false,                        /* header byte order is little */
938
939   (HAS_RELOC | EXEC_P |         /* object flags */
940    HAS_LINENO | HAS_DEBUG |
941    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
942
943   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* sect
944                                                             flags */
945   0,                            /* leading underscore */
946   ' ',                          /* ar_pad_char */
947   15,                           /* ar_max_namelen */
948   4,                            /* minimum alignment power */
949   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
950      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
951      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
952   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
953      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
954      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
955
956   {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
957      ecoff_archive_p, _bfd_dummy_target},
958   {bfd_false, ecoff_mkobject,  /* bfd_set_format */
959      _bfd_generic_mkarchive, bfd_false},
960   {bfd_false, ecoff_write_object_contents, /* bfd_write_contents */
961      _bfd_write_archive_contents, bfd_false},
962   JUMP_TABLE (ecoff),
963   (PTR) &mips_ecoff_backend_data
964 };
965
966 bfd_target ecoff_big_vec =
967 {
968   "ecoff-bigmips",              /* name */
969   bfd_target_ecoff_flavour,
970   true,                         /* data byte order is big */
971   true,                         /* header byte order is big */
972
973   (HAS_RELOC | EXEC_P |         /* object flags */
974    HAS_LINENO | HAS_DEBUG |
975    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
976
977   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* sect flags */
978   0,                            /* leading underscore */
979   ' ',                          /* ar_pad_char */
980   15,                           /* ar_max_namelen */
981   4,                            /* minimum alignment power */
982   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
983      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
984      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
985   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
986      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
987      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
988  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
989     ecoff_archive_p, ecoff_core_file_p},
990  {bfd_false, ecoff_mkobject, /* bfd_set_format */
991     _bfd_generic_mkarchive, bfd_false},
992  {bfd_false, ecoff_write_object_contents, /* bfd_write_contents */
993     _bfd_write_archive_contents, bfd_false},
994   JUMP_TABLE(ecoff),
995   (PTR) &mips_ecoff_backend_data
996   /* Note that there is another bfd_target just above this one.  If
997      you are adding initializers here, you should be adding them there
998      as well.  */
999 };