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