Some of these are guesses, if you know different, just yell.
[external/binutils.git] / bfd / coff-rs6000.c
1 /* IBM RS/6000 "XCOFF" back-end for BFD.
2    Copyright (C) 1990, 1991 Free Software Foundation, Inc.
3    Written by Metin G. Ozisik, Mimi Phûông-Thåo Võ, and John Gilmore.
4    Archive support from Damon A. Permezel.
5    Contributed by IBM Corporation and Cygnus Support.
6
7 This file is part of BFD, the Binary File Descriptor library.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23 /* This port currently only handles reading object files, except when
24    compiled on an RS/6000 host.  -- no archive support, no core files.
25    In all cases, it does not support writing.
26
27    FIXMEmgo comments are left from Metin Ozisik's original port.  */
28
29 /* Internalcoff.h and coffcode.h modify themselves based on this flag.  */
30 #define RS6000COFF_C 1
31
32 #include "bfd.h"
33 #include "sysdep.h"
34 #include "libbfd.h"
35 #include "obstack.h"
36 #include "coff/internal.h"
37 #include "coff/rs6000.h"
38 #include "libcoff.h"
39
40 /* The main body of code is in coffcode.h.  */
41
42 /* Can't read rs6000 relocs */
43 #define RTYPE2HOWTO(a,b)
44 #include "coffcode.h"
45
46 #define coff_archive_p          bfd_generic_archive_p
47 #define coff_mkarchive          _bfd_generic_mkarchive
48
49 #ifdef ARCHIVES_PLEASE
50
51 /* ------------------------------------------------------------------------ */
52 /*      Support for archive file stuff..                                    */
53 /*      Stolen from Damon A. Permezel's `bfd' portation.                    */
54 /* ------------------------------------------------------------------------ */
55
56 #undef  coff_openr_next_archived_file
57 #define coff_openr_next_archived_file   rs6000coff_openr_next_archived_file
58
59 #undef  coff_write_armap
60 #define coff_write_armap                rs6000coff_write_armap
61
62 #undef  coff_stat_arch_elt
63 #define coff_stat_arch_elt              rs6000coff_stat_arch_elt
64
65 #undef  coff_snarf_ar_hdr
66 #define coff_snarf_ar_hdr               rs6000coff_snarf_ar_hdr
67
68 #undef  coff_mkarchive
69 #define coff_mkarchive                  rs6000coff_mkarchive
70
71 #undef  coff_archive_p
72 #define coff_archive_p                  rs6000coff_archive_p
73
74 #include "/usr/include/ar.h"            /* <ar.h> doesn't do it.        */
75
76
77 #define arch_hdr(bfd)           \
78         ((struct ar_hdr *)      \
79          (((struct areltdata *)((bfd)->arelt_data))->arch_header))
80
81
82 static boolean
83 rs6000coff_mkarchive (abfd)
84      bfd *abfd;
85 {
86         bfd_error = invalid_operation;  /* write not supported  */
87 }
88
89
90 /* This functions reads an arch header and returns an areltdata pointer, or
91    NULL on error.
92
93    Presumes the file pointer is already in the right place (ie pointing
94    to the ar_hdr in the file).   Moves the file pointer; on success it
95    should be pointing to the front of the file contents; on failure it
96    could have been moved arbitrarily.
97 */
98
99 struct areltdata *
100 rs6000coff_snarf_ar_hdr (abfd)
101      bfd *abfd;
102 {
103         extern int errno;
104
105         struct {
106                 struct ar_hdr hdr;
107                 char namebuf[256];
108         } h;
109         int size;
110         struct areltdata *ared;
111         unsigned int namelen = 0;
112         char *allocptr;
113
114         size = sizeof (h.hdr);
115         if (bfd_read(&h.hdr, 1, size, abfd) != size) {
116                 bfd_error = no_more_archived_files;
117                 return NULL;
118         }
119         size  = atoi(h.hdr.ar_namlen);  /* ar_name[] length     */
120         size += size & 1;
121
122         if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) {
123                 bfd_error = no_more_archived_files;
124                 return NULL;
125         }
126
127         if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
128                 bfd_error = malformed_archive;
129                 return NULL;
130         }
131
132         h.hdr._ar_name.ar_name[size] = 0;       /* terminate filename   */
133
134         /*
135          * if the filename is NULL, we're (probably) at the end.
136          */
137         if (size == 0) {
138                 bfd_error = no_more_archived_files;
139                 return NULL;
140         }
141
142         size += sizeof (h.hdr);
143         allocptr = bfd_zalloc(abfd, sizeof (*ared) + size);
144
145         if (allocptr == NULL) {
146                 bfd_error = no_memory;
147                 return NULL;
148         }
149
150         ared = (struct areltdata *) allocptr;
151
152         ared->arch_header = (void *) (allocptr + sizeof (struct areltdata));
153         memcpy ((char *) ared->arch_header, &h.hdr, size);
154         ared->parsed_size = atoi(h.hdr.ar_size);
155         ared->filename    = ((AR_HDR*) ared->arch_header)->_ar_name.ar_name;
156
157         return ared;
158 }
159
160 /* Stolen directly from archive.c, except it calls rs6000coff_snarf_ar_hdr.
161    Why wasn't this part of the transfer vector?  */
162
163 bfd *
164 rs6000coff_get_elt_at_filepos (archive, filepos)
165      bfd *archive;
166      file_ptr filepos;
167 {
168   struct areltdata *new_areldata;
169   bfd *n_nfd;
170
171   n_nfd = look_for_bfd_in_cache (archive, filepos);
172   if (n_nfd) return n_nfd;
173
174   if (0 > bfd_seek (archive, filepos, SEEK_SET)) {
175     bfd_error = system_call_error;
176     return NULL;
177   }
178
179   if ((new_areldata = rs6000coff_snarf_ar_hdr (archive)) == NULL) return NULL;
180   
181   n_nfd = _bfd_create_empty_archive_element_shell (archive);
182   if (n_nfd == NULL) {
183     bfd_release (archive, (PTR)new_areldata);
184     return NULL;
185   }
186   n_nfd->origin = bfd_tell (archive);
187   n_nfd->arelt_data = (PTR) new_areldata;
188   n_nfd->filename = new_areldata->filename;
189
190   if (add_bfd_to_cache (archive, filepos, n_nfd))
191     return n_nfd;
192
193   /* huh? */
194   bfd_release (archive, (PTR)n_nfd);
195   bfd_release (archive, (PTR)new_areldata);
196   return NULL;
197 }
198
199 /*
200  * xcoff_openr_next_archived_file -     xcoff has nxt/prv seek addrs.
201  */
202 static bfd *
203 rs6000coff_openr_next_archived_file(archive, last_file)
204   bfd *archive, *last_file; 
205 {
206         file_ptr filestart;
207
208         if (!last_file)
209                 filestart = bfd_ardata(archive)->first_file_filepos;
210         else
211                 filestart = atol(arch_hdr(last_file)->ar_nxtmem);
212
213         return rs6000coff_get_elt_at_filepos (archive, filestart);
214 }
215
216
217 static bfd_target *
218 rs6000coff_archive_p (abfd)
219      bfd *abfd;
220 {
221         struct fl_hdr hdr;
222         register struct artdata *art;
223
224         if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) {
225                 bfd_error = wrong_format;
226                 return 0;
227         }
228
229         if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
230                 bfd_error = wrong_format;
231                 return 0;
232         }
233
234         /*
235          * bfd_ardata() accesses the bfd->tdata field.
236          */
237         abfd->tdata.aout_ar_data =
238           (void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr));
239         if ((art = bfd_ardata (abfd)) == NULL) {
240                 bfd_error = no_memory;
241                 return 0;
242         }
243
244         art->first_file_filepos = atoi(hdr.fl_fstmoff);
245         *(struct fl_hdr *) (1 + art) = hdr;
246
247         /* Someday...
248          * slurp in the member table, which I think is the armap equivalent.
249         xcoff_slurp_armap(abfd);
250          */
251   
252         return abfd->xvec;
253 }
254
255
256 static int
257 rs6000coff_stat_arch_elt(abfd, buf)
258   bfd *abfd;
259   struct stat *buf;
260 {
261         struct ar_hdr *hdr;
262         char *aloser;
263   
264         if (abfd->arelt_data == NULL) {
265                 bfd_error = invalid_operation;
266                 return -1;
267         }
268     
269         hdr = arch_hdr (abfd);
270
271 #define foo(arelt, stelt, size)  \
272         buf->stelt = strtol (hdr->arelt, &aloser, size); \
273                 if (aloser == hdr->arelt) return -1;
274   
275         foo (ar_date, st_mtime, 10);
276         foo (ar_uid, st_uid, 10);
277         foo (ar_gid, st_gid, 10);
278         foo (ar_mode, st_mode, 8);
279         foo (ar_size, st_size, 10);
280 #undef foo
281
282         return 0;
283 }
284
285 static boolean
286 rs6000coff_write_armap (arch, elength, map, orl_count, stridx)
287   bfd *arch;
288   unsigned int elength;
289   struct orl *map; 
290 {
291         bfd_error = invalid_operation;
292         return false;
293 }
294 #endif  /* ARCHIVES_PLEASE */
295
296 \f
297 #ifdef COREFILES_PLEASE
298 extern bfd_target * rs6000coff_core_p ();
299 extern boolean rs6000coff_get_section_contents ();
300 extern boolean rs6000coff_core_file_matches_executable_p ();
301
302 #undef  coff_core_file_matches_executable_p
303 #define coff_core_file_matches_executable_p  \
304                                      rs6000coff_core_file_matches_executable_p
305
306 #undef  coff_get_section_contents
307 #define coff_get_section_contents       rs6000coff_get_section_contents
308 #endif
309
310 /* The transfer vector that leads the outside world to all of the above. */
311
312 bfd_target rs6000coff_vec =
313 {
314   "aixcoff-rs6000",             /* name */
315   bfd_target_coff_flavour,      
316   true,                         /* data byte order is big */
317   true,                         /* header byte order is big */
318
319   (HAS_RELOC | EXEC_P |         /* object flags */
320    HAS_LINENO | HAS_DEBUG |
321    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
322
323   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
324   0,                            /* leading char */
325   '/',                          /* ar_pad_char */
326   15,                           /* ar_max_namelen??? FIXMEmgo */
327   3,                            /* default alignment power */
328
329   _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* data */
330   _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* hdrs */
331
332   {_bfd_dummy_target, coff_object_p,    /* bfd_check_format */
333      coff_archive_p,
334 #ifdef  COREFILES_PLEASE
335      rs6000coff_core_p
336 #else
337      _bfd_dummy_target
338 #endif
339        },
340   {bfd_false, coff_mkobject, coff_mkarchive, /* bfd_set_format */
341      bfd_false},
342   {bfd_false, coff_write_object_contents,       /* bfd_write_contents */
343      _bfd_write_archive_contents, bfd_false},
344
345   JUMP_TABLE(coff),
346   COFF_SWAP_TABLE
347 };