binutils-gdb/bfd/coff-rs6000.c

373 lines
9.6 KiB
C
Raw Normal View History

/* BFD back-end for IBM RS/6000 "XCOFF" files.
Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
FIXME: Can someone provide a transliteration of this name into ASCII?
Using the following chars caused a compiler warning on HIUX (so I replaced
them with octal escapes), and isn't useful without an understanding of what
character set it is.
Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365,
and John Gilmore.
1991-10-25 15:16:56 +08:00
Archive support from Damon A. Permezel.
Contributed by IBM Corporation and Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This port currently only handles reading object files, except when
compiled on an RS/6000 host. -- no archive support, no core files.
In all cases, it does not support writing.
FIXMEmgo comments are left from Metin Ozisik's original port. */
1991-10-25 15:16:56 +08:00
/* Internalcoff.h and coffcode.h modify themselves based on this flag. */
#define RS6000COFF_C 1
#include "bfd.h"
#include "sysdep.h"
1991-10-25 15:16:56 +08:00
#include "libbfd.h"
#include "obstack.h"
#include "coff/internal.h"
#include "coff/rs6000.h"
1991-10-25 15:16:56 +08:00
#include "libcoff.h"
/* The main body of code is in coffcode.h. */
/* Can't read rs6000 relocs */
static reloc_howto_type dummy_reloc =
HOWTO (0, /* type */
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
0, /* special_function */
"UNKNOWN", /* name */
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
false); /* pcrel_offset */
#define RTYPE2HOWTO(cache_ptr, dst) cache_ptr->howto = &dummy_reloc;
#include "coffcode.h"
1991-10-25 15:16:56 +08:00
#define coff_archive_p bfd_generic_archive_p
#define coff_mkarchive _bfd_generic_mkarchive
1991-10-25 15:16:56 +08:00
#ifdef ARCHIVES_PLEASE
1991-10-25 15:16:56 +08:00
/* ------------------------------------------------------------------------ */
/* Support for archive file stuff.. */
/* Stolen from Damon A. Permezel's `bfd' portation. */
/* ------------------------------------------------------------------------ */
1991-10-25 15:16:56 +08:00
#undef coff_openr_next_archived_file
#define coff_openr_next_archived_file rs6000coff_openr_next_archived_file
1991-10-25 15:16:56 +08:00
#undef coff_write_armap
#define coff_write_armap rs6000coff_write_armap
1991-10-25 15:16:56 +08:00
#undef coff_stat_arch_elt
#define coff_stat_arch_elt rs6000coff_stat_arch_elt
1991-10-25 15:16:56 +08:00
#undef coff_snarf_ar_hdr
#define coff_snarf_ar_hdr rs6000coff_snarf_ar_hdr
1991-10-25 15:16:56 +08:00
#undef coff_mkarchive
#define coff_mkarchive rs6000coff_mkarchive
1991-10-25 15:16:56 +08:00
#undef coff_archive_p
#define coff_archive_p rs6000coff_archive_p
1991-10-25 15:16:56 +08:00
#include "/usr/include/ar.h" /* <ar.h> doesn't do it. */
#define arch_hdr(bfd) \
((struct ar_hdr *) \
(((struct areltdata *)((bfd)->arelt_data))->arch_header))
static boolean
rs6000coff_mkarchive (abfd)
bfd *abfd;
{
bfd_error = invalid_operation; /* write not supported */
}
/* This functions reads an arch header and returns an areltdata pointer, or
NULL on error.
Presumes the file pointer is already in the right place (ie pointing
to the ar_hdr in the file). Moves the file pointer; on success it
should be pointing to the front of the file contents; on failure it
could have been moved arbitrarily.
*/
struct areltdata *
rs6000coff_snarf_ar_hdr (abfd)
bfd *abfd;
{
extern int errno;
struct {
struct ar_hdr hdr;
char namebuf[256];
} h;
int size;
struct areltdata *ared;
unsigned int namelen = 0;
char *allocptr;
size = sizeof (h.hdr);
if (bfd_read(&h.hdr, 1, size, abfd) != size) {
bfd_error = no_more_archived_files;
return NULL;
}
size = atoi(h.hdr.ar_namlen); /* ar_name[] length */
size += size & 1;
if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) {
bfd_error = no_more_archived_files;
return NULL;
}
if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
bfd_error = malformed_archive;
return NULL;
}
h.hdr._ar_name.ar_name[size] = 0; /* terminate filename */
/*
* if the filename is NULL, we're (probably) at the end.
*/
if (size == 0) {
bfd_error = no_more_archived_files;
return NULL;
}
size += sizeof (h.hdr);
allocptr = bfd_zalloc(abfd, sizeof (*ared) + size);
if (allocptr == NULL) {
bfd_error = no_memory;
return NULL;
}
ared = (struct areltdata *) allocptr;
ared->arch_header = (void *) (allocptr + sizeof (struct areltdata));
memcpy ((char *) ared->arch_header, &h.hdr, size);
ared->parsed_size = atoi(h.hdr.ar_size);
ared->filename = ((AR_HDR*) ared->arch_header)->_ar_name.ar_name;
return ared;
}
/* Stolen directly from archive.c, except it calls rs6000coff_snarf_ar_hdr.
Why wasn't this part of the transfer vector? */
bfd *
rs6000coff_get_elt_at_filepos (archive, filepos)
bfd *archive;
file_ptr filepos;
{
struct areltdata *new_areldata;
bfd *n_nfd;
n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
if (n_nfd) return n_nfd;
if (0 != bfd_seek (archive, filepos, SEEK_SET)) {
bfd_error = system_call_error;
return NULL;
}
if ((new_areldata = rs6000coff_snarf_ar_hdr (archive)) == NULL) return NULL;
n_nfd = _bfd_create_empty_archive_element_shell (archive);
if (n_nfd == NULL) {
bfd_release (archive, (PTR)new_areldata);
return NULL;
}
n_nfd->origin = bfd_tell (archive);
n_nfd->arelt_data = (PTR) new_areldata;
n_nfd->filename = new_areldata->filename;
if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
return n_nfd;
/* huh? */
bfd_release (archive, (PTR)n_nfd);
bfd_release (archive, (PTR)new_areldata);
return NULL;
}
1991-10-25 15:16:56 +08:00
/*
* xcoff_openr_next_archived_file - xcoff has nxt/prv seek addrs.
*/
static bfd *
rs6000coff_openr_next_archived_file(archive, last_file)
bfd *archive, *last_file;
{
file_ptr filestart;
if (!last_file)
filestart = bfd_ardata(archive)->first_file_filepos;
else
filestart = atol(arch_hdr(last_file)->ar_nxtmem);
return rs6000coff_get_elt_at_filepos (archive, filestart);
1991-10-25 15:16:56 +08:00
}
static bfd_target *
rs6000coff_archive_p (abfd)
bfd *abfd;
{
struct fl_hdr hdr;
register struct artdata *art;
if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) {
1991-10-25 15:16:56 +08:00
bfd_error = wrong_format;
return 0;
}
if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
bfd_error = wrong_format;
return 0;
}
/*
* bfd_ardata() accesses the bfd->tdata field.
*/
abfd->tdata.aout_ar_data =
(void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr));
1991-10-25 15:16:56 +08:00
if ((art = bfd_ardata (abfd)) == NULL) {
bfd_error = no_memory;
return 0;
}
art->first_file_filepos = atoi(hdr.fl_fstmoff);
*(struct fl_hdr *) (1 + art) = hdr;
/* Someday...
* slurp in the member table, which I think is the armap equivalent.
1991-10-25 15:16:56 +08:00
xcoff_slurp_armap(abfd);
*/
return abfd->xvec;
}
static int
rs6000coff_stat_arch_elt(abfd, buf)
bfd *abfd;
struct stat *buf;
{
struct ar_hdr *hdr;
char *aloser;
if (abfd->arelt_data == NULL) {
bfd_error = invalid_operation;
return -1;
}
hdr = arch_hdr (abfd);
#define foo(arelt, stelt, size) \
buf->stelt = strtol (hdr->arelt, &aloser, size); \
if (aloser == hdr->arelt) return -1;
foo (ar_date, st_mtime, 10);
foo (ar_uid, st_uid, 10);
foo (ar_gid, st_gid, 10);
foo (ar_mode, st_mode, 8);
foo (ar_size, st_size, 10);
#undef foo
1991-10-25 15:16:56 +08:00
return 0;
}
static boolean
rs6000coff_write_armap (arch, elength, map, orl_count, stridx)
bfd *arch;
unsigned int elength;
struct orl *map;
{
bfd_error = invalid_operation;
return false;
}
#endif /* ARCHIVES_PLEASE */
#ifdef COREFILES_PLEASE
extern bfd_target * rs6000coff_core_p ();
extern boolean rs6000coff_get_section_contents ();
extern boolean rs6000coff_core_file_matches_executable_p ();
#undef coff_core_file_matches_executable_p
#define coff_core_file_matches_executable_p \
rs6000coff_core_file_matches_executable_p
1991-10-25 15:16:56 +08:00
#undef coff_get_section_contents
#define coff_get_section_contents rs6000coff_get_section_contents
1991-10-25 15:16:56 +08:00
#endif
/* The transfer vector that leads the outside world to all of the above. */
bfd_target rs6000coff_vec =
{
"aixcoff-rs6000", /* name */
bfd_target_coff_flavour,
true, /* data byte order is big */
true, /* header byte order is big */
(HAS_RELOC | EXEC_P | /* object flags */
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | WP_TEXT),
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
0, /* leading char */
'/', /* ar_pad_char */
15, /* ar_max_namelen??? FIXMEmgo */
3, /* default alignment power */
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
{_bfd_dummy_target, coff_object_p, /* bfd_check_format */
coff_archive_p,
#ifdef COREFILES_PLEASE
rs6000coff_core_p
#else
_bfd_dummy_target
#endif
},
{bfd_false, coff_mkobject, coff_mkarchive, /* bfd_set_format */
bfd_false},
{bfd_false, coff_write_object_contents, /* bfd_write_contents */
_bfd_write_archive_contents, bfd_false},
JUMP_TABLE(coff),
COFF_SWAP_TABLE,
};