/* BFD back-end for IBM RS/6000 "XCOFF" files.
- Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. */
-
/* Internalcoff.h and coffcode.h modify themselves based on this flag. */
#define RS6000COFF_C 1
#include "coff/rs6000.h"
#include "libcoff.h"
+static boolean xcoff_slurp_armap PARAMS ((bfd *));
+static const bfd_target *xcoff_archive_p PARAMS ((bfd *));
+static PTR xcoff_read_ar_hdr PARAMS ((bfd *));
+static bfd *xcoff_openr_next_archived_file PARAMS ((bfd *, bfd *));
+static int xcoff_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
+static const char *normalize_filename PARAMS ((bfd *));
+static boolean xcoff_write_armap
+ PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
+static boolean xcoff_write_archive_contents PARAMS ((bfd *));
+
/* The main body of code is in coffcode.h. */
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
#define COFF_LONG_FILENAMES
#include "coffcode.h"
+\f
+/* XCOFF archive support. The original version of this code was by
+ Damon A. Permezel. It was enhanced to permit cross support, and
+ writing archive files, by Ian Lance Taylor, Cygnus Support.
+
+ XCOFF uses its own archive format. Everything is hooked together
+ with file offset links, so it is possible to rapidly update an
+ archive in place. Of course, we don't do that. An XCOFF archive
+ has a real file header, not just an ARMAG string. The structure of
+ the file header and of each archive header appear below.
+
+ An XCOFF archive also has a member table, which is a list of
+ elements in the archive (you can get that by looking through the
+ linked list, but you have to read a lot more of the file). The
+ member table has a normal archive header with an empty name. It is
+ normally (and perhaps must be) the second to last entry in the
+ archive. The member table data is almost printable ASCII. It
+ starts with a 12 character decimal string which is the number of
+ entries in the table. For each entry it has a 12 character decimal
+ string which is the offset in the archive of that member. These
+ entries are followed by a series of null terminated strings which
+ are the member names for each entry.
+
+ Finally, an XCOFF archive has a global symbol table, which is what
+ we call the armap. The global symbol table has a normal archive
+ header with an empty name. It is normally (and perhaps must be)
+ the last entry in the archive. The contents start with a four byte
+ binary number which is the number of entries. This is followed by
+ a that many four byte binary numbers; each is the file offset of an
+ entry in the archive. These numbers are followed by a series of
+ null terminated strings, which are symbol names. */
+
+/* XCOFF archives use this as a magic string. */
+
+#define XCOFFARMAG "<aiaff>\012"
+#define SXCOFFARMAG 8
+
+/* This terminates an XCOFF archive member name. */
+
+#define XCOFFARFMAG "`\012"
+#define SXCOFFARFMAG 2
+
+/* XCOFF archives start with this (printable) structure. */
+
+struct xcoff_ar_file_hdr
+{
+ /* Magic string. */
+ char magic[SXCOFFARMAG];
+
+ /* Offset of the member table (decimal ASCII string). */
+ char memoff[12];
+
+ /* Offset of the global symbol table (decimal ASCII string). */
+ char symoff[12];
+
+ /* Offset of the first member in the archive (decimal ASCII string). */
+ char firstmemoff[12];
+
+ /* Offset of the last member in the archive (decimal ASCII string). */
+ char lastmemoff[12];
+
+ /* Offset of the first member on the free list (decimal ASCII
+ string). */
+ char freeoff[12];
+};
-#define coff_archive_p bfd_generic_archive_p
-#define coff_mkarchive _bfd_generic_mkarchive
+#define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG)
-#ifdef HOST_AIX
+/* Each XCOFF archive member starts with this (printable) structure. */
+
+struct xcoff_ar_hdr
+{
+ /* File size not including the header (decimal ASCII string). */
+ char size[12];
+
+ /* File offset of next archive member (decimal ASCII string). */
+ char nextoff[12];
+
+ /* File offset of previous archive member (decimal ASCII string). */
+ char prevoff[12];
+
+ /* File mtime (decimal ASCII string). */
+ char date[12];
+
+ /* File UID (decimal ASCII string). */
+ char uid[12];
+
+ /* File GID (decimal ASCII string). */
+ char gid[12];
+
+ /* File mode (octal ASCII string). */
+ char mode[12];
+
+ /* Length of file name (decimal ASCII string). */
+ char namlen[4];
+
+ /* This structure is followed by the file name. The length of the
+ name is given in the namlen field. If the length of the name is
+ odd, the name is followed by a null byte. The name and optional
+ null byte are followed by XCOFFARFMAG, which is not included in
+ namlen. The contents of the archive member follow; the number of
+ bytes is given in the size field. */
+};
-/* ------------------------------------------------------------------------ */
-/* Support for archive file stuff.. */
-/* Stolen from Damon A. Permezel's `bfd' portation. */
-/* ------------------------------------------------------------------------ */
+#define SIZEOF_AR_HDR (7 * 12 + 4)
-#define rs6000coff_slurp_armap bfd_slurp_coff_armap
-#define rs6000coff_slurp_extended_name_table _bfd_slurp_extended_name_table
-#define rs6000coff_construct_extended_name_table \
- _bfd_archive_coff_construct_extended_name_table
-#define rs6000coff_truncate_arname bfd_dont_truncate_arname
-#define rs6000coff_update_armap_timestamp bfd_true
+/* We store a copy of the xcoff_ar_file_hdr in the tdata field of the
+ artdata structure. */
+#define xcoff_ardata(abfd) \
+ ((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata)
-#undef coff_mkarchive
-#define coff_mkarchive rs6000coff_mkarchive
+/* We store a copy of the xcoff_ar_hdr in the arelt_data field of an
+ archive element. */
+#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
+#define arch_xhdr(bfd) \
+ ((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header)
-#undef coff_archive_p
-#define coff_archive_p rs6000coff_archive_p
+/* XCOFF archives do not have anything which corresponds to an
+ extended name table. */
-#include "/usr/include/ar.h" /* <ar.h> doesn't do it. */
+#define xcoff_slurp_extended_name_table bfd_false
+#define xcoff_construct_extended_name_table \
+ ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \
+ bfd_false)
+#define xcoff_truncate_arname bfd_dont_truncate_arname
+/* XCOFF archives do not have a timestamp. */
-#define arch_hdr(bfd) \
- ((struct ar_hdr *) \
- (((struct areltdata *)((bfd)->arelt_data))->arch_header))
+#define xcoff_update_armap_timestamp bfd_true
+/* Read in the armap of an XCOFF archive. */
static boolean
-rs6000coff_mkarchive (abfd)
+xcoff_slurp_armap (abfd)
bfd *abfd;
{
- bfd_set_error (bfd_error_invalid_operation); /* write not supported */
- return false;
-}
+ file_ptr off;
+ struct xcoff_ar_hdr hdr;
+ size_t namlen;
+ bfd_size_type sz;
+ bfd_byte *contents, *cend;
+ unsigned int c, i;
+ carsym *arsym;
+ bfd_byte *p;
+
+ if (xcoff_ardata (abfd) == NULL)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10);
+ if (off == 0)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ if (bfd_seek (abfd, off, SEEK_SET) != 0)
+ return false;
+
+ /* The symbol table starts with a normal archive header. */
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
+ return false;
+
+ /* Skip the name (normally empty). */
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0)
+ return false;
+
+ /* Read in the entire symbol table. */
+ sz = strtol (hdr.size, (char **) NULL, 10);
+ contents = (bfd_byte *) bfd_alloc (abfd, sz);
+ if (contents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ if (bfd_read ((PTR) contents, 1, sz, abfd) != sz)
+ return false;
+
+ /* The symbol table starts with a four byte count. */
+ c = bfd_h_get_32 (abfd, contents);
+
+ if (c * 4 >= sz)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ bfd_ardata (abfd)->symdefs = ((carsym *)
+ bfd_alloc (abfd, c * sizeof (carsym)));
+ if (bfd_ardata (abfd)->symdefs == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ /* After the count comes a list of four byte file offsets. */
+ for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4;
+ i < c;
+ ++i, ++arsym, p += 4)
+ arsym->file_offset = bfd_h_get_32 (abfd, p);
+
+ /* After the file offsets come null terminated symbol names. */
+ cend = contents + sz;
+ for (i = 0, arsym = bfd_ardata (abfd)->symdefs;
+ i < c;
+ ++i, ++arsym, p += strlen ((char *) p) + 1)
+ {
+ if (p >= cend)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ arsym->name = (char *) p;
+ }
+ bfd_ardata (abfd)->symdef_count = c;
+ bfd_has_map (abfd) = true;
-/* This functions reads an arch header and returns an areltdata pointer, or
- NULL on error.
+ return true;
+}
- 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.
-*/
+/* See if this is an XCOFF archive. */
-struct areltdata *
-rs6000coff_snarf_ar_hdr (abfd)
+static const bfd_target *
+xcoff_archive_p (abfd)
bfd *abfd;
{
- struct {
- struct ar_hdr hdr;
- char namebuf[256];
- } h;
- int size;
- struct areltdata *ared;
- char *allocptr;
-
- size = sizeof (h.hdr);
- if (bfd_read(&h.hdr, 1, size, abfd) != size) {
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_no_more_archived_files);
- return NULL;
- }
- size = atoi(h.hdr.ar_namlen); /* ar_name[] length */
- size += size & 1;
+ struct xcoff_ar_file_hdr hdr;
- if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) {
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_no_more_archived_files);
- return NULL;
- }
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_FILE_HDR, 1, abfd)
+ != SIZEOF_AR_FILE_HDR)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
- if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
- bfd_set_error (bfd_error_malformed_archive);
- return NULL;
- }
+ if (strncmp (hdr.magic, XCOFFARMAG, SXCOFFARMAG) != 0)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
- h.hdr._ar_name.ar_name[size] = 0; /* terminate filename */
+ /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
+ involves a cast, we can't do it as the left operand of
+ assignment. */
+ abfd->tdata.aout_ar_data =
+ (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata));
- /*
- * if the filename is NULL, we're (probably) at the end.
- */
- if (size == 0) {
- bfd_set_error (bfd_error_no_more_archived_files);
- return NULL;
- }
+ if (bfd_ardata (abfd) == (struct artdata *) NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
- size += sizeof (h.hdr);
- allocptr = bfd_zalloc(abfd, sizeof (*ared) + size);
+ bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
+ (char **) NULL, 10);
+ bfd_ardata (abfd)->cache = NULL;
+ bfd_ardata (abfd)->archive_head = NULL;
+ bfd_ardata (abfd)->symdefs = NULL;
+ bfd_ardata (abfd)->extended_names = NULL;
- if (allocptr == NULL) {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR);
+ if (bfd_ardata (abfd)->tdata == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
- ared = (struct areltdata *) allocptr;
+ memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
- 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;
+ if (! xcoff_slurp_armap (abfd))
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = (struct artdata *) NULL;
+ return NULL;
+ }
- return ared;
+ return abfd->xvec;
}
-/* Stolen directly from archive.c, except it calls rs6000coff_snarf_ar_hdr.
- Why wasn't this part of the transfer vector? */
+/* Read the archive header in an XCOFF archive. */
-bfd *
-rs6000coff_get_elt_at_filepos (archive, filepos)
- bfd *archive;
- file_ptr filepos;
+static PTR
+xcoff_read_ar_hdr (abfd)
+ bfd *abfd;
{
- struct areltdata *new_areldata;
- bfd *n_nfd;
-
- n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
- if (n_nfd) return n_nfd;
+ struct xcoff_ar_hdr hdr;
+ size_t namlen;
+ struct xcoff_ar_hdr *hdrp;
+ struct areltdata *ret;
- if (0 != bfd_seek (archive, filepos, SEEK_SET))
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
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);
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ hdrp = bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1);
+ if (hdrp == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
+ if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen)
return NULL;
- }
- n_nfd->origin = bfd_tell (archive);
- n_nfd->arelt_data = (PTR) new_areldata;
- n_nfd->filename = new_areldata->filename;
+ ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0';
- if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
- return n_nfd;
+ ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata));
+ if (ret == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ ret->arch_header = (char *) hdrp;
+ ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
+ ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
+
+ /* Skip over the XCOFFARFMAG at the end of the file name. */
+ if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0)
+ return NULL;
- /* huh? */
- bfd_release (archive, (PTR)n_nfd);
- bfd_release (archive, (PTR)new_areldata);
- return NULL;
+ return (PTR) ret;
}
-/*
- * xcoff_openr_next_archived_file - xcoff has nxt/prv seek addrs.
- */
+/* Open the next element in an XCOFF archive. */
+
static bfd *
-rs6000coff_openr_next_archived_file(archive, last_file)
- bfd *archive, *last_file;
+xcoff_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
{
- file_ptr filestart;
+ file_ptr filestart;
+
+ if (xcoff_ardata (archive) == NULL)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ if (last_file == NULL)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, 10);
- if (!last_file)
- filestart = bfd_ardata(archive)->first_file_filepos;
- else
- filestart = atol(arch_hdr(last_file)->ar_nxtmem);
+ if (filestart == 0
+ || filestart == strtol (xcoff_ardata (archive)->memoff,
+ (char **) NULL, 10)
+ || filestart == strtol (xcoff_ardata (archive)->symoff,
+ (char **) NULL, 10))
+ {
+ bfd_set_error (bfd_error_no_more_archived_files);
+ return NULL;
+ }
- return rs6000coff_get_elt_at_filepos (archive, filestart);
+ return _bfd_get_elt_at_filepos (archive, filestart);
}
+/* Stat an element in an XCOFF archive. */
-static const bfd_target *
-rs6000coff_archive_p (abfd)
+int
+xcoff_generic_stat_arch_elt (abfd, s)
bfd *abfd;
+ struct stat *s;
{
- struct fl_hdr hdr;
- register struct artdata *art;
+ struct xcoff_ar_hdr *hdrp;
- if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) {
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_wrong_format);
- return 0;
- }
+ if (abfd->arelt_data == NULL)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
- if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
- bfd_set_error (bfd_error_wrong_format);
- return 0;
- }
+ hdrp = arch_xhdr (abfd);
- /*
- * bfd_ardata() accesses the bfd->tdata field.
- */
- abfd->tdata.aout_ar_data =
- (void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr));
- if ((art = bfd_ardata (abfd)) == NULL) {
- bfd_set_error (bfd_error_no_memory);
- return 0;
- }
+ s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
+ s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
+ s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
+ s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
+ s->st_size = arch_eltdata (abfd)->parsed_size;
- art->first_file_filepos = atoi(hdr.fl_fstmoff);
- *(struct fl_hdr *) (1 + art) = hdr;
+ return 0;
+}
- /* Someday...
- * slurp in the member table, which I think is the armap equivalent.
- xcoff_slurp_armap(abfd);
- */
-
- return abfd->xvec;
+/* Normalize a file name for inclusion in an archive. */
+
+static const char *
+normalize_filename (abfd)
+ bfd *abfd;
+{
+ const char *file;
+ const char *filename;
+
+ file = bfd_get_filename (abfd);
+ filename = strrchr (file, '/');
+ if (filename != NULL)
+ filename++;
+ else
+ filename = file;
+ return filename;
}
+/* Write out an XCOFF armap. */
-static int
-rs6000coff_generic_stat_arch_elt(abfd, buf)
- bfd *abfd;
- struct stat *buf;
+/*ARGSUSED*/
+static boolean
+xcoff_write_armap (abfd, elength, map, orl_count, stridx)
+ bfd *abfd;
+ unsigned int elength;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
{
- struct ar_hdr *hdr;
- char *aloser;
+ struct xcoff_ar_hdr hdr;
+ char *p;
+ char buf[4];
+ bfd *sub;
+ file_ptr fileoff;
+ unsigned int i;
+
+ memset (&hdr, 0, sizeof hdr);
+ sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx));
+ sprintf (hdr.nextoff, "%d", 0);
+ memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12);
+ sprintf (hdr.date, "%d", 0);
+ sprintf (hdr.uid, "%d", 0);
+ sprintf (hdr.gid, "%d", 0);
+ sprintf (hdr.mode, "%d", 0);
+ sprintf (hdr.namlen, "%d", 0);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR
+ || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG)
+ return false;
- if (abfd->arelt_data == NULL) {
- bfd_set_error (bfd_error_invalid_operation);
- return -1;
+ bfd_h_put_32 (abfd, orl_count, buf);
+ if (bfd_write (buf, 1, 4, abfd) != 4)
+ return false;
+
+ sub = abfd->archive_head;
+ fileoff = SIZEOF_AR_FILE_HDR;
+ i = 0;
+ while (sub != NULL && i < orl_count)
+ {
+ size_t namlen;
+
+ while (((bfd *) (map[i]).pos) == sub)
+ {
+ bfd_h_put_32 (abfd, fileoff, buf);
+ if (bfd_write (buf, 1, 4, abfd) != 4)
+ return false;
+ ++i;
}
-
- hdr = arch_hdr (abfd);
+ namlen = strlen (normalize_filename (sub));
+ namlen = (namlen + 1) &~ 1;
+ fileoff += (SIZEOF_AR_HDR
+ + namlen
+ + SXCOFFARFMAG
+ + arelt_size (sub));
+ fileoff = (fileoff + 1) &~ 1;
+ sub = sub->next;
+ }
-#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
-
- return 0;
+ for (i = 0; i < orl_count; i++)
+ {
+ const char *name;
+ size_t namlen;
+
+ name = *map[i].name;
+ namlen = strlen (name);
+ if (bfd_write (name, 1, namlen + 1, abfd) != namlen + 1)
+ return false;
+ }
+
+ if ((stridx & 1) != 0)
+ {
+ char b;
+
+ b = '\0';
+ if (bfd_write (&b, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
}
+/* Write out an XCOFF archive. We always write an entire archive,
+ rather than fussing with the freelist and so forth. */
+
static boolean
-rs6000coff_write_armap (arch, elength, map, orl_count, stridx)
- bfd *arch;
- unsigned int elength;
- struct orl *map;
- unsigned int orl_count;
- int stridx;
+xcoff_write_archive_contents (abfd)
+ bfd *abfd;
{
- bfd_set_error (bfd_error_invalid_operation);
+ struct xcoff_ar_file_hdr fhdr;
+ size_t count;
+ size_t total_namlen;
+ file_ptr *offsets;
+ boolean makemap;
+ boolean hasobjects;
+ file_ptr prevoff, nextoff;
+ bfd *sub;
+ unsigned int i;
+ struct xcoff_ar_hdr ahdr;
+ bfd_size_type size;
+ char *p;
+ char decbuf[13];
+
+ memset (&fhdr, 0, sizeof fhdr);
+ strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG);
+ sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR);
+ sprintf (fhdr.freeoff, "%d", 0);
+
+ count = 0;
+ total_namlen = 0;
+ for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
+ {
+ ++count;
+ total_namlen += strlen (normalize_filename (sub)) + 1;
+ }
+ offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
+ if (offsets == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR, SEEK_SET) != 0)
+ return false;
+
+ makemap = bfd_has_map (abfd);
+ hasobjects = false;
+ prevoff = 0;
+ nextoff = SIZEOF_AR_FILE_HDR;
+ for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++)
+ {
+ const char *name;
+ size_t namlen;
+ struct xcoff_ar_hdr *ahdrp;
+ bfd_size_type remaining;
+
+ if (makemap && ! hasobjects)
+ {
+ if (bfd_check_format (sub, bfd_object))
+ hasobjects = true;
+ }
+
+ name = normalize_filename (sub);
+ namlen = strlen (name);
+
+ if (sub->arelt_data != NULL)
+ ahdrp = arch_xhdr (sub);
+ else
+ ahdrp = NULL;
+
+ if (ahdrp == NULL)
+ {
+ struct stat s;
+
+ memset (&ahdr, 0, sizeof ahdr);
+ ahdrp = &ahdr;
+ if (stat (bfd_get_filename (sub), &s) != 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return NULL;
+ }
+
+ sprintf (ahdrp->size, "%ld", (long) s.st_size);
+ sprintf (ahdrp->date, "%ld", (long) s.st_mtime);
+ sprintf (ahdrp->uid, "%ld", (long) s.st_uid);
+ sprintf (ahdrp->gid, "%ld", (long) s.st_gid);
+ sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode);
+
+ if (sub->arelt_data == NULL)
+ {
+ sub->arelt_data = ((struct areltdata *)
+ bfd_alloc (sub, sizeof (struct areltdata)));
+ if (sub->arelt_data == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ }
+
+ arch_eltdata (sub)->parsed_size = s.st_size;
+ }
+
+ sprintf (ahdrp->prevoff, "%ld", (long) prevoff);
+ sprintf (ahdrp->namlen, "%ld", (long) namlen);
+
+ /* If the length of the name is odd, we write out the null byte
+ after the name as well. */
+ namlen = (namlen + 1) &~ 1;
+
+ remaining = arelt_size (sub);
+ size = (SIZEOF_AR_HDR
+ + namlen
+ + SXCOFFARFMAG
+ + remaining);
+
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+
+ offsets[i] = nextoff;
+
+ prevoff = nextoff;
+ nextoff += size + (size & 1);
+
+ sprintf (ahdrp->nextoff, "%ld", (long) nextoff);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR
+ || bfd_write ((PTR) name, 1, namlen, abfd) != namlen
+ || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd)
+ != SXCOFFARFMAG))
return false;
-}
-#endif /* HOST_AIX */
+ if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+ while (remaining != 0)
+ {
+ bfd_size_type amt;
+ bfd_byte buffer[DEFAULT_BUFFERSIZE];
+
+ amt = sizeof buffer;
+ if (amt > remaining)
+ amt = remaining;
+ if (bfd_read (buffer, 1, amt, sub) != amt
+ || bfd_write (buffer, 1, amt, abfd) != amt)
+ return false;
+ remaining -= amt;
+ }
+
+ if ((size & 1) != 0)
+ {
+ bfd_byte b;
+
+ b = '\0';
+ if (bfd_write (&b, 1, 1, abfd) != 1)
+ return false;
+ }
+ }
+
+ sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
+
+ /* Write out the member table. */
+
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+ sprintf (fhdr.memoff, "%ld", (long) nextoff);
+
+ memset (&ahdr, 0, sizeof ahdr);
+ sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen));
+ sprintf (ahdr.prevoff, "%ld", (long) prevoff);
+ sprintf (ahdr.date, "%d", 0);
+ sprintf (ahdr.uid, "%d", 0);
+ sprintf (ahdr.gid, "%d", 0);
+ sprintf (ahdr.mode, "%d", 0);
+ sprintf (ahdr.namlen, "%d", 0);
+
+ size = (SIZEOF_AR_HDR
+ + 12
+ + count * 12
+ + total_namlen
+ + SXCOFFARFMAG);
+
+ prevoff = nextoff;
+ nextoff += size + (size & 1);
+
+ if (makemap && hasobjects)
+ sprintf (ahdr.nextoff, "%ld", (long) nextoff);
+ else
+ sprintf (ahdr.nextoff, "%d", 0);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR
+ || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd)
+ != SXCOFFARFMAG))
+ return false;
+
+ sprintf (decbuf, "%-12ld", (long) count);
+ if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12)
+ return false;
+ for (i = 0; i < count; i++)
+ {
+ sprintf (decbuf, "%-12ld", (long) offsets[i]);
+ if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12)
+ return false;
+ }
+ for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
+ {
+ const char *name;
+ size_t namlen;
+
+ name = normalize_filename (sub);
+ namlen = strlen (name);
+ if (bfd_write ((PTR) name, 1, namlen + 1, abfd) != namlen + 1)
+ return false;
+ }
+ if ((size & 1) != 0)
+ {
+ bfd_byte b;
+
+ b = '\0';
+ if (bfd_write ((PTR) &b, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ /* Write out the armap, if appropriate. */
+
+ if (! makemap || ! hasobjects)
+ sprintf (fhdr.symoff, "%d", 0);
+ else
+ {
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+ sprintf (fhdr.symoff, "%ld", (long) nextoff);
+ bfd_ardata (abfd)->tdata = (PTR) &fhdr;
+ if (! _bfd_compute_and_write_armap (abfd, 0))
+ return false;
+ }
+
+ /* Write out the archive file header. */
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+ || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR, 1, abfd) !=
+ SIZEOF_AR_FILE_HDR))
+ return false;
+
+ return true;
+}
\f
#define CORE_FILE_P _bfd_dummy_target
#define coff_core_file_matches_executable_p \
rs6000coff_core_file_matches_executable_p
+extern char *rs6000coff_core_file_failing_command PARAMS ((bfd *abfd));
+#undef coff_core_file_failing_command
+#define coff_core_file_failing_command rs6000coff_core_file_failing_command
+
+extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd));
+#undef coff_core_file_failing_signal
+#define coff_core_file_failing_signal rs6000coff_core_file_failing_signal
+
#undef coff_get_section_contents
#define coff_get_section_contents rs6000coff_get_section_contents
#endif /* AIX_CORE */
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
{_bfd_dummy_target, coff_object_p, /* bfd_check_format */
- coff_archive_p, CORE_FILE_P},
- {bfd_false, coff_mkobject, coff_mkarchive, /* bfd_set_format */
- bfd_false},
+ xcoff_archive_p, CORE_FILE_P},
+ {bfd_false, coff_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
{bfd_false, coff_write_object_contents, /* bfd_write_contents */
- _bfd_write_archive_contents, bfd_false},
+ xcoff_write_archive_contents, bfd_false},
BFD_JUMP_TABLE_GENERIC (coff),
BFD_JUMP_TABLE_COPY (coff),
BFD_JUMP_TABLE_CORE (coff),
-#ifdef HOST_AIX
- BFD_JUMP_TABLE_ARCHIVE (rs6000coff),
-#else
- BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
-#endif
+ BFD_JUMP_TABLE_ARCHIVE (xcoff),
BFD_JUMP_TABLE_SYMBOLS (coff),
BFD_JUMP_TABLE_RELOCS (coff),
BFD_JUMP_TABLE_WRITE (coff),