* ecoff.c: New file for generic ECOFF functions.
[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 \f
45
46 /* ECOFF has COFF sections, but the debugging information is stored in
47    a completely different format.  ECOFF targets use some of the
48    swapping routines from coffswap.h, and some of the generic COFF
49    routines in coffgen.c, but, unlike the real COFF targets, do not
50    use coffcode.h itself.
51
52    Get the generic COFF swapping routines, except for the reloc,
53    symbol, and lineno ones.  Give them ecoff names.  */
54 #define MIPSECOFF
55 #define NO_COFF_RELOCS
56 #define NO_COFF_SYMBOLS
57 #define NO_COFF_LINENOS
58 #define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in
59 #define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out
60 #define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in
61 #define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out
62 #define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in
63 #define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out
64 #include "coffswap.h"
65
66 /* Get the ECOFF swapping routines.  */
67 #define ECOFF_32
68 #include "ecoffswap.h"
69 \f
70 /* This is the ECOFF backend structure.  The backend_data field of the
71    ecoff_tdata structure is set to this when an ECOFF BFD is
72    initialized.  This is used by the generic ECOFF routines.  */
73
74 static const struct ecoff_backend_data mips_ecoff_backend_data =
75 {
76   /* Supported architecture.  */
77   bfd_arch_mips,
78   /* Big endian magic number.  */
79   MIPS_MAGIC_BIG,
80   /* Little endian magic number.  */
81   MIPS_MAGIC_LITTLE,
82   /* Alignment of debugging information.  E.g., 4.  */
83   4,
84   /* The page boundary used to align sections in a demand-paged
85      executable file.  E.g., 0x1000.  */
86   0x1000,
87   /* Bitsize of constructor entries.  */
88   32,
89   /* Sizes of external symbolic information.  */
90   sizeof (struct hdr_ext),
91   sizeof (struct dnr_ext),
92   sizeof (struct pdr_ext),
93   sizeof (struct sym_ext),
94   sizeof (struct opt_ext),
95   sizeof (struct fdr_ext),
96   sizeof (struct rfd_ext),
97   sizeof (struct ext_ext),
98   /* Functions to swap in external symbolic data.  */
99   ecoff_swap_hdr_in,
100   ecoff_swap_dnr_in,
101   ecoff_swap_pdr_in,
102   ecoff_swap_sym_in,
103   ecoff_swap_opt_in,
104   ecoff_swap_fdr_in,
105   ecoff_swap_rfd_in,
106   ecoff_swap_ext_in,
107   /* Functions to swap out external symbolic data.  */
108   ecoff_swap_hdr_out,
109   ecoff_swap_dnr_out,
110   ecoff_swap_pdr_out,
111   ecoff_swap_sym_out,
112   ecoff_swap_opt_out,
113   ecoff_swap_fdr_out,
114   ecoff_swap_rfd_out,
115   ecoff_swap_ext_out,
116   /* External reloc size.  */
117   RELSZ,
118   /* Reloc swapping functions.  */
119   mips_ecoff_swap_reloc_in,
120   mips_ecoff_swap_reloc_out
121 };
122 \f
123 /* See whether the magic number matches.  */
124
125 static boolean
126 mips_ecoff_bad_format_hook (abfd, filehdr)
127      bfd *abfd;
128      PTR filehdr;
129 {
130   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
131
132   if (MIPS_ECOFF_BADMAG (*internal_f))
133     return false;
134
135   return true;
136 }
137
138 /* Create an ECOFF object.  */
139
140 static boolean
141 mips_ecoff_mkobject (abfd)
142      bfd *abfd;
143 {
144   abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
145                                 bfd_zalloc (abfd, sizeof (ecoff_data_type)));
146   if (abfd->tdata.ecoff_obj_data == NULL)
147     {
148       bfd_error = no_memory;
149       return false;
150     }
151
152   ecoff_data (abfd)->backend_data = &mips_ecoff_backend_data;
153
154   /* Always create a .scommon section for every BFD.  This is a hack so
155      that the linker has something to attach scSCommon symbols to.  */
156   bfd_make_section (abfd, SCOMMON);
157
158   return true;
159 }
160
161 /* Create the MIPS ECOFF backend specific information.  */
162
163 static PTR
164 mips_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
165      bfd *abfd;
166      PTR filehdr;
167      PTR aouthdr;
168 {
169   struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
170   struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
171   ecoff_data_type *ecoff;
172
173   if (mips_ecoff_mkobject (abfd) == false)
174     return NULL;
175
176   ecoff = ecoff_data (abfd);
177   ecoff->gp_size = 8;
178   ecoff->sym_filepos = internal_f->f_symptr;
179
180   if (internal_a != (struct internal_aouthdr *) NULL)
181     {
182       int i;
183
184       ecoff->text_start = internal_a->text_start;
185       ecoff->text_end = internal_a->text_start + internal_a->tsize;
186       ecoff->gp = internal_a->gp_value;
187       ecoff->gprmask = internal_a->gprmask;
188       for (i = 0; i < 4; i++)
189         ecoff->cprmask[i] = internal_a->cprmask[i];
190       if (internal_a->magic == ECOFF_AOUT_ZMAGIC)
191         abfd->flags |= D_PAGED;
192     }
193
194   return (PTR) ecoff;
195 }
196 \f
197 /* Reloc handling.  MIPS ECOFF relocs are packed into 8 bytes in
198    external form.  They use a bit which indicates whether the symbol
199    is external.  */
200
201 /* Swap a reloc in.  */
202
203 static void
204 mips_ecoff_swap_reloc_in (abfd, ext_ptr, intern)
205      bfd *abfd;
206      PTR ext_ptr;
207      struct internal_reloc *intern;
208 {
209   const RELOC *ext = (RELOC *) ext_ptr;
210
211   intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
212   if (abfd->xvec->header_byteorder_big_p != false)
213     {
214       intern->r_symndx = (((int) ext->r_bits[0]
215                            << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
216                           | ((int) ext->r_bits[1]
217                              << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
218                           | ((int) ext->r_bits[2]
219                              << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
220       intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
221                         >> RELOC_BITS3_TYPE_SH_BIG);
222       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
223     }
224   else
225     {
226       intern->r_symndx = (((int) ext->r_bits[0]
227                            << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
228                           | ((int) ext->r_bits[1]
229                              << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
230                           | ((int) ext->r_bits[2]
231                              << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
232       intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
233                         >> RELOC_BITS3_TYPE_SH_LITTLE);
234       intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
235     }
236 }
237
238 /* Swap a reloc out.  */
239
240 static void
241 mips_ecoff_swap_reloc_out (abfd, intern, dst)
242      bfd *abfd;
243      const struct internal_reloc *intern;
244      PTR dst;
245 {
246   RELOC *ext = (RELOC *) dst;
247
248   bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
249   if (abfd->xvec->header_byteorder_big_p != false)
250     {
251       ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
252       ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
253       ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
254       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
255                          & RELOC_BITS3_TYPE_BIG)
256                         | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
257     }
258   else
259     {
260       ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
261       ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
262       ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
263       ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
264                          & RELOC_BITS3_TYPE_LITTLE)
265                         | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
266     }
267 }
268 \f
269 #ifdef HOST_IRIX4
270
271 #include <core.out.h>
272
273 struct sgi_core_struct 
274 {
275   int sig;
276   char cmd[CORE_NAMESIZE];
277 };
278
279 #define core_hdr(bfd) ((bfd)->tdata.sgi_core_data)
280 #define core_signal(bfd) (core_hdr(bfd)->sig)
281 #define core_command(bfd) (core_hdr(bfd)->cmd)
282
283 static asection *
284 make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos)
285      bfd *abfd;
286      CONST char *name;
287      flagword flags;
288      bfd_size_type _raw_size;
289      bfd_vma vma;
290      file_ptr filepos;
291 {
292   asection *asect;
293
294   asect = bfd_make_section (abfd, name);
295   if (!asect)
296     return NULL;
297
298   asect->flags = flags;
299   asect->_raw_size = _raw_size;
300   asect->vma = vma;
301   asect->filepos = filepos;
302   asect->alignment_power = 4;
303
304   return asect;
305 }
306
307 static bfd_target *
308 ecoff_core_file_p (abfd)
309      bfd *abfd;
310 {
311   int val;
312   int i;
313   char *secname;
314   struct coreout coreout;
315   struct idesc *idg, *idf, *ids;
316
317   val = bfd_read ((PTR)&coreout, 1, sizeof coreout, abfd);
318   if (val != sizeof coreout)
319     return 0;
320
321   if (coreout.c_magic != CORE_MAGIC
322       || coreout.c_version != CORE_VERSION1)
323     return 0;
324
325   core_hdr (abfd) = (struct sgi_core_struct *) bfd_zalloc (abfd, sizeof (struct sgi_core_struct));
326   if (!core_hdr (abfd))
327     return NULL;
328
329   strncpy (core_command (abfd), coreout.c_name, CORE_NAMESIZE);
330   core_signal (abfd) = coreout.c_sigcause;
331
332   bfd_seek (abfd, coreout.c_vmapoffset, SEEK_SET);
333
334   for (i = 0; i < coreout.c_nvmap; i++)
335     {
336       struct vmap vmap;
337
338       val = bfd_read ((PTR)&vmap, 1, sizeof vmap, abfd);
339       if (val != sizeof vmap)
340         break;
341
342       switch (vmap.v_type)
343         {
344         case VDATA:
345           secname = ".data";
346           break;
347         case VSTACK:
348           secname = ".stack";
349           break;
350         default:
351           continue;
352         }
353
354       if (!make_bfd_asection (abfd, secname,
355                               SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS,
356                               vmap.v_len,
357                               vmap.v_vaddr,
358                               vmap.v_offset,
359                               2))
360         return NULL;
361     }
362
363   /* Make sure that the regs are contiguous within the core file. */
364
365   idg = &coreout.c_idesc[I_GPREGS];
366   idf = &coreout.c_idesc[I_FPREGS];
367   ids = &coreout.c_idesc[I_SPECREGS];
368
369   if (idg->i_offset + idg->i_len != idf->i_offset
370       || idf->i_offset + idf->i_len != ids->i_offset)
371     return 0;                   /* Can't deal with non-contig regs */
372
373   bfd_seek (abfd, idg->i_offset, SEEK_SET);
374
375   make_bfd_asection (abfd, ".reg",
376                      SEC_ALLOC+SEC_HAS_CONTENTS,
377                      idg->i_len + idf->i_len + ids->i_len,
378                      0,
379                      idg->i_offset);
380
381   /* OK, we believe you.  You're a core file (sure, sure).  */
382
383   return abfd->xvec;
384 }
385
386 static char *
387 ecoff_core_file_failing_command (abfd)
388      bfd *abfd;
389 {
390   return core_command (abfd);
391 }
392
393 static int
394 ecoff_core_file_failing_signal (abfd)
395      bfd *abfd;
396 {
397   return core_signal (abfd);
398 }
399
400 static boolean
401 ecoff_core_file_matches_executable_p (core_bfd, exec_bfd)
402      bfd *core_bfd, *exec_bfd;
403 {
404   return true;                  /* XXX - FIXME */
405 }
406 #else /* not def HOST_IRIX4 */
407 #define ecoff_core_file_p _bfd_dummy_target
408 #define ecoff_core_file_failing_command _bfd_dummy_core_file_failing_command
409 #define ecoff_core_file_failing_signal _bfd_dummy_core_file_failing_signal
410 #define ecoff_core_file_matches_executable_p \
411   _bfd_dummy_core_file_matches_executable_p
412 #endif
413 \f
414 /* This is the COFF backend structure.  The backend_data field of the
415    bfd_target structure is set to this.  The section reading code in
416    coffgen.c uses this structure.  */
417
418 static CONST bfd_coff_backend_data mips_ecoff_std_swap_table = {
419   (void (*) PARAMS ((bfd *,PTR,int,int,PTR))) bfd_void, /* aux_in */
420   (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
421   (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */
422   (unsigned (*) PARAMS ((bfd *,PTR,int,int,PTR))) bfd_void, /* aux_out */
423   (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */
424   (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */
425   (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
426   mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
427   mips_ecoff_swap_scnhdr_out,
428   FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, true,
429   mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
430   mips_ecoff_swap_scnhdr_in, mips_ecoff_bad_format_hook,
431   ecoff_set_arch_mach_hook, mips_ecoff_mkobject_hook,
432   ecoff_styp_to_sec_flags, ecoff_make_section_hook, ecoff_set_alignment_hook,
433   ecoff_slurp_symbol_table
434 };
435
436 bfd_target ecoff_little_vec =
437 {
438   "ecoff-littlemips",           /* name */
439   bfd_target_ecoff_flavour,
440   false,                        /* data byte order is little */
441   false,                        /* header byte order is little */
442
443   (HAS_RELOC | EXEC_P |         /* object flags */
444    HAS_LINENO | HAS_DEBUG |
445    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
446
447   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* sect
448                                                             flags */
449   0,                            /* leading underscore */
450   ' ',                          /* ar_pad_char */
451   15,                           /* ar_max_namelen */
452   4,                            /* minimum alignment power */
453   _do_getl64, _do_getl_signed_64, _do_putl64,
454      _do_getl32, _do_getl_signed_32, _do_putl32,
455      _do_getl16, _do_getl_signed_16, _do_putl16, /* data */
456   _do_getl64, _do_getl_signed_64, _do_putl64,
457      _do_getl32, _do_getl_signed_32, _do_putl32,
458      _do_getl16, _do_getl_signed_16, _do_putl16, /* hdrs */
459
460   {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
461      ecoff_archive_p, _bfd_dummy_target},
462   {bfd_false, mips_ecoff_mkobject,  /* bfd_set_format */
463      _bfd_generic_mkarchive, bfd_false},
464   {bfd_false, ecoff_write_object_contents, /* bfd_write_contents */
465      _bfd_write_archive_contents, bfd_false},
466   JUMP_TABLE (ecoff),
467   (PTR) &mips_ecoff_std_swap_table
468 };
469
470 bfd_target ecoff_big_vec =
471 {
472   "ecoff-bigmips",              /* name */
473   bfd_target_ecoff_flavour,
474   true,                         /* data byte order is big */
475   true,                         /* header byte order is big */
476
477   (HAS_RELOC | EXEC_P |         /* object flags */
478    HAS_LINENO | HAS_DEBUG |
479    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
480
481   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* sect flags */
482   0,                            /* leading underscore */
483   ' ',                          /* ar_pad_char */
484   15,                           /* ar_max_namelen */
485   4,                            /* minimum alignment power */
486   _do_getb64, _do_getb_signed_64, _do_putb64,
487      _do_getb32, _do_getb_signed_32, _do_putb32,
488      _do_getb16, _do_getb_signed_16, _do_putb16,
489   _do_getb64, _do_getb_signed_64, _do_putb64,
490      _do_getb32, _do_getb_signed_32, _do_putb32,
491      _do_getb16, _do_getb_signed_16, _do_putb16,
492  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
493     ecoff_archive_p, ecoff_core_file_p},
494  {bfd_false, mips_ecoff_mkobject, /* bfd_set_format */
495     _bfd_generic_mkarchive, bfd_false},
496  {bfd_false, ecoff_write_object_contents, /* bfd_write_contents */
497     _bfd_write_archive_contents, bfd_false},
498   JUMP_TABLE(ecoff),
499   (PTR) &mips_ecoff_std_swap_table
500   /* Note that there is another bfd_target just above this one.  If
501      you are adding initializers here, you should be adding them there
502      as well.  */
503 };