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