* h8300-dis.c: Fix formatting.
[binutils-gdb.git] / bfd / coff-rs6000.c
index 10047dea1ac6e008620c68623b1076dc08db7f00..46894001a7bb2c75986e3f4269ab545f2439f37e 100644 (file)
@@ -1,5 +1,6 @@
 /* BFD back-end for IBM RS/6000 "XCOFF" files.
-   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   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
@@ -23,34 +24,404 @@ 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.  */
+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 "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
-#include "obstack.h"
 #include "coff/internal.h"
 #include "coff/rs6000.h"
 #include "libcoff.h"
+#define TARGET_NAME "aixcoff-rs6000"
+#define TARGET_SYM rs6000coff_vec
+#include "xcoff-target.h"
+
 
 /* The main body of code is in coffcode.h.  */
 
+static const char *normalize_filename PARAMS ((bfd *));
+
+/* We use our own tdata type.  Its first field is the COFF tdata type,
+   so the COFF routines are compatible.  */
+
+boolean
+_bfd_xcoff_mkobject (abfd)
+     bfd *abfd;
+{
+  coff_data_type *coff;
+
+  abfd->tdata.xcoff_obj_data =
+    ((struct xcoff_tdata *)
+     bfd_zalloc (abfd, sizeof (struct xcoff_tdata)));
+  if (abfd->tdata.xcoff_obj_data == NULL)
+    return false;
+  coff = coff_data (abfd);
+  coff->symbols = (coff_symbol_type *) NULL;
+  coff->conversion_table = (unsigned int *) NULL;
+  coff->raw_syments = (struct coff_ptr_struct *) NULL;
+  coff->relocbase = 0;
+
+  xcoff_data (abfd)->modtype = ('1' << 8) | 'L';
+
+  /* We set cputype to -1 to indicate that it has not been
+     initialized.  */
+  xcoff_data (abfd)->cputype = -1;
+
+  xcoff_data (abfd)->csects = NULL;
+  xcoff_data (abfd)->debug_indices = NULL;
+
+  return true;
+}
+
+/* Copy XCOFF data from one BFD to another.  */
+
+boolean
+_bfd_xcoff_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  struct xcoff_tdata *ix, *ox;
+  asection *sec;
+
+  if (ibfd->xvec != obfd->xvec)
+    return true;
+  ix = xcoff_data (ibfd);
+  ox = xcoff_data (obfd);
+  ox->full_aouthdr = ix->full_aouthdr;
+  ox->toc = ix->toc;
+  if (ix->sntoc == 0)
+    ox->sntoc = 0;
+  else
+    {
+      sec = coff_section_from_bfd_index (ibfd, ix->sntoc);
+      if (sec == NULL)
+       ox->sntoc = 0;
+      else
+       ox->sntoc = sec->output_section->target_index;
+    }
+  if (ix->snentry == 0)
+    ox->snentry = 0;
+  else
+    {
+      sec = coff_section_from_bfd_index (ibfd, ix->snentry);
+      if (sec == NULL)
+       ox->snentry = 0;
+      else
+       ox->snentry = sec->output_section->target_index;
+    }
+  ox->text_align_power = ix->text_align_power;
+  ox->data_align_power = ix->data_align_power;
+  ox->modtype = ix->modtype;
+  ox->cputype = ix->cputype;
+  ox->maxdata = ix->maxdata;
+  ox->maxstack = ix->maxstack;
+  return true;
+}
+
+/* I don't think XCOFF really has a notion of local labels based on
+   name.  This will mean that ld -X doesn't actually strip anything.
+   The AIX native linker does not have a -X option, and it ignores the
+   -x option.  */
+
+boolean
+_bfd_xcoff_is_local_label_name (abfd, name)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+{
+  return false;
+}
+\f
+
+
+void
+_bfd_xcoff_swap_sym_in (abfd, ext1, in1)
+     bfd            *abfd;
+     PTR ext1;
+     PTR in1;
+{
+  SYMENT *ext = (SYMENT *)ext1;
+  struct internal_syment      *in = (struct internal_syment *)in1;
+
+
+  if(ext->e.e_name[0] != 0)
+    {
+      memcpy(in->_n._n_name, ext->e.e_name, SYMNMLEN);
+    }
+  else 
+    {
+      in->_n._n_n._n_zeroes = 0;
+      in->_n._n_n._n_offset = 
+         bfd_h_get_32(abfd, (bfd_byte *) ext->e.e.e_offset);
+    }
+
+  in->n_value = bfd_h_get_32(abfd, (bfd_byte *) ext->e_value); 
+  in->n_scnum = bfd_h_get_16(abfd, (bfd_byte *) ext->e_scnum);
+  in->n_type = bfd_h_get_16(abfd, (bfd_byte *) ext->e_type);
+  in->n_sclass = bfd_h_get_8(abfd, ext->e_sclass);
+  in->n_numaux = bfd_h_get_8(abfd, ext->e_numaux);
+}
+
+unsigned int
+_bfd_xcoff_swap_sym_out (abfd, inp, extp)
+     bfd       *abfd;
+     PTR       inp;
+     PTR       extp;
+{
+  struct internal_syment *in = (struct internal_syment *)inp;
+  SYMENT *ext =(SYMENT *)extp;
+
+  if(in->_n._n_name[0] != 0)
+    {
+      memcpy(ext->e.e_name, in->_n._n_name, SYMNMLEN);
+    }
+  else
+    {
+      bfd_h_put_32(abfd, 0, (bfd_byte *) ext->e.e.e_zeroes);
+      bfd_h_put_32(abfd, in->_n._n_n._n_offset, 
+             (bfd_byte *)  ext->e.e.e_offset);
+    }
+
+  bfd_h_put_32(abfd,  in->n_value , (bfd_byte *) ext->e_value);
+  bfd_h_put_16(abfd,  in->n_scnum , (bfd_byte *) ext->e_scnum);
+  bfd_h_put_16(abfd,  in->n_type , (bfd_byte *) ext->e_type);
+  bfd_h_put_8(abfd,  in->n_sclass , ext->e_sclass);
+  bfd_h_put_8(abfd,  in->n_numaux , ext->e_numaux);
+  return bfd_coff_symesz (abfd);
+}
+
+#define PUTWORD bfd_h_put_32
+#define PUTHALF bfd_h_put_16
+#define PUTBYTE bfd_h_put_8
+#define GETWORD bfd_h_get_32
+#define GETHALF bfd_h_get_16
+#define GETBYTE bfd_h_get_8
+
+void
+_bfd_xcoff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1)
+     bfd            *abfd;
+     PTR             ext1;
+     int             type;
+     int             class;
+     int             indx;
+     int             numaux;
+     PTR             in1;
+{
+  AUXENT    *ext = (AUXENT *)ext1;
+  union internal_auxent *in = (union internal_auxent *)in1;
+
+  switch (class) {
+    case C_FILE:
+      if (ext->x_file.x_fname[0] == 0) {
+         in->x_file.x_n.x_zeroes = 0;
+         in->x_file.x_n.x_offset = 
+          bfd_h_get_32(abfd, (bfd_byte *) ext->x_file.x_n.x_offset);
+       } else {
+           if (numaux > 1)
+             {
+               if (indx == 0)
+                 memcpy (in->x_file.x_fname, ext->x_file.x_fname,
+                         numaux * sizeof (AUXENT));
+             }
+           else
+             {
+               memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN);
+             }
+         }
+      goto end;
+
+      /* RS/6000 "csect" auxents */
+    case C_EXT:
+    case C_HIDEXT:
+      if (indx + 1 == numaux)
+       {
+         in->x_csect.x_scnlen.l = 
+             bfd_h_get_32 (abfd, ext->x_csect.x_scnlen);
+         in->x_csect.x_parmhash = bfd_h_get_32 (abfd,
+                                                ext->x_csect.x_parmhash);
+         in->x_csect.x_snhash   = bfd_h_get_16 (abfd, ext->x_csect.x_snhash);
+         /* We don't have to hack bitfields in x_smtyp because it's
+            defined by shifts-and-ands, which are equivalent on all
+            byte orders.  */
+         in->x_csect.x_smtyp    = bfd_h_get_8  (abfd, ext->x_csect.x_smtyp);
+         in->x_csect.x_smclas   = bfd_h_get_8  (abfd, ext->x_csect.x_smclas);
+         in->x_csect.x_stab     = bfd_h_get_32 (abfd, ext->x_csect.x_stab);
+         in->x_csect.x_snstab   = bfd_h_get_16 (abfd, ext->x_csect.x_snstab);
+         goto end;
+       }
+      break;
+
+    case C_STAT:
+    case C_LEAFSTAT:
+    case C_HIDDEN:
+      if (type == T_NULL) {
+         in->x_scn.x_scnlen = bfd_h_get_32(abfd, 
+                 (bfd_byte *) ext->x_scn.x_scnlen);
+         in->x_scn.x_nreloc = bfd_h_get_16(abfd, 
+                 (bfd_byte *) ext->x_scn.x_nreloc);
+         in->x_scn.x_nlinno = bfd_h_get_16(abfd, 
+                 (bfd_byte *) ext->x_scn.x_nlinno);
+         /* PE defines some extra fields; we zero them out for
+             safety.  */
+         in->x_scn.x_checksum = 0;
+         in->x_scn.x_associated = 0;
+         in->x_scn.x_comdat = 0;
+
+         goto end;
+       }
+      break;
+    }
+
+  in->x_sym.x_tagndx.l = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_tagndx);
+  in->x_sym.x_tvndx = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_tvndx);
+
+  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
+    {
+      in->x_sym.x_fcnary.x_fcn.x_lnnoptr = bfd_h_get_32(abfd, (bfd_byte *)
+             ext->x_sym.x_fcnary.x_fcn.x_lnnoptr);
+      in->x_sym.x_fcnary.x_fcn.x_endndx.l = bfd_h_get_32(abfd, (bfd_byte *)
+             ext->x_sym.x_fcnary.x_fcn.x_endndx);
+    }
+  else
+    {
+      in->x_sym.x_fcnary.x_ary.x_dimen[0] =
+       bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
+      in->x_sym.x_fcnary.x_ary.x_dimen[1] =
+       bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
+      in->x_sym.x_fcnary.x_ary.x_dimen[2] =
+       bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
+      in->x_sym.x_fcnary.x_ary.x_dimen[3] =
+       bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
+    }
+  if (ISFCN(type)) {
+    in->x_sym.x_misc.x_fsize = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_fsize);
+  }
+  else {
+    in->x_sym.x_misc.x_lnsz.x_lnno = bfd_h_get_16(abfd, (bfd_byte *)
+           ext->x_sym.x_misc.x_lnsz.x_lnno);
+    in->x_sym.x_misc.x_lnsz.x_size = bfd_h_get_16(abfd, (bfd_byte *)
+           ext->x_sym.x_misc.x_lnsz.x_size);
+  }
+
+end: ;
+  /* the semicolon is because MSVC doesn't like labels at
+     end of block. */
+
+}
+
+
+
+unsigned int
+_bfd_xcoff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp)
+     bfd   *abfd;
+     PTR       inp;
+     int   type;
+     int   class;
+     int   indx ATTRIBUTE_UNUSED;
+     int   numaux ATTRIBUTE_UNUSED;
+     PTR       extp;
+{
+  union internal_auxent *in = (union internal_auxent *)inp;
+  AUXENT *ext = (AUXENT *)extp;
+
+  memset((PTR)ext, 0, bfd_coff_auxesz (abfd));
+  switch (class)
+    {
+  case C_FILE:
+    if (in->x_file.x_fname[0] == 0)
+      {
+      PUTWORD(abfd, 0, (bfd_byte *) ext->x_file.x_n.x_zeroes);
+      PUTWORD(abfd,
+             in->x_file.x_n.x_offset,
+             (bfd_byte *) ext->x_file.x_n.x_offset);
+    }
+    else
+      {
+      memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN);
+      }
+    goto end;
+
+  /* RS/6000 "csect" auxents */
+  case C_EXT:
+  case C_HIDEXT:
+    if (indx + 1 == numaux)
+      {
+       PUTWORD (abfd, in->x_csect.x_scnlen.l,ext->x_csect.x_scnlen);
+       PUTWORD (abfd, in->x_csect.x_parmhash,  ext->x_csect.x_parmhash);
+       PUTHALF (abfd, in->x_csect.x_snhash,    ext->x_csect.x_snhash);
+       /* We don't have to hack bitfields in x_smtyp because it's
+          defined by shifts-and-ands, which are equivalent on all
+          byte orders.  */
+       PUTBYTE (abfd, in->x_csect.x_smtyp,     ext->x_csect.x_smtyp);
+       PUTBYTE (abfd, in->x_csect.x_smclas,    ext->x_csect.x_smclas);
+       PUTWORD (abfd, in->x_csect.x_stab,      ext->x_csect.x_stab);
+       PUTHALF (abfd, in->x_csect.x_snstab,    ext->x_csect.x_snstab);
+       goto end;
+      }
+    break;
+
+  case C_STAT:
+  case C_LEAFSTAT:
+  case C_HIDDEN:
+    if (type == T_NULL) {
+      bfd_h_put_32(abfd, in->x_scn.x_scnlen, (bfd_byte *) ext->x_scn.x_scnlen);
+      bfd_h_put_16(abfd, in->x_scn.x_nreloc, (bfd_byte *) ext->x_scn.x_nreloc);
+      bfd_h_put_16(abfd, in->x_scn.x_nlinno, (bfd_byte *) ext->x_scn.x_nlinno);
+      goto end;
+    }
+    break;
+  }
+
+  PUTWORD(abfd, in->x_sym.x_tagndx.l, (bfd_byte *) ext->x_sym.x_tagndx);
+  PUTWORD(abfd, in->x_sym.x_tvndx , (bfd_byte *) ext->x_sym.x_tvndx);
+
+  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
+    {
+      bfd_h_put_32(abfd,  in->x_sym.x_fcnary.x_fcn.x_lnnoptr, 
+             (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr);
+      PUTWORD(abfd,  in->x_sym.x_fcnary.x_fcn.x_endndx.l, 
+             (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx);
+    }
+  else
+    {
+      bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0],
+                   (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
+      bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1],
+                   (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
+      bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2],
+                   (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
+      bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3],
+                   (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
+    }
+
+  if (ISFCN (type))
+    PUTWORD (abfd, in->x_sym.x_misc.x_fsize,
+            (bfd_byte *)  ext->x_sym.x_misc.x_fsize);
+  else
+    {
+      bfd_h_put_16(abfd, in->x_sym.x_misc.x_lnsz.x_lnno, 
+             (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_lnno);
+      bfd_h_put_16(abfd, in->x_sym.x_misc.x_lnsz.x_size, 
+             (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_size);
+    }
+
+end:
+  return bfd_coff_auxesz (abfd);
+}
+
+
+\f
 /* The XCOFF reloc table.  Actually, XCOFF relocations specify the
    bitsize and whether they are signed or not, along with a
    conventional type.  This table is for the types, which are used for
    different algorithms for putting in the reloc.  Many of these
    relocs need special_function entries, which I have not written.  */
 
-static reloc_howto_type rs6000coff_howto_table[] =
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
+   from smaller values.  Start with zero, widen, *then* decrement.  */
+#define MINUS_ONE       (((bfd_vma)0) - 1)
+
+reloc_howto_type xcoff_howto_table[] =
 {
   /* Standard 32 bit relocation.  */
   HOWTO (0,                    /* type */                                 
@@ -104,7 +475,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         16,                    /* bitsize */                   
         false,                 /* pc_relative */                          
         0,                     /* bitpos */                               
-        complain_overflow_signed, /* complain_on_overflow */
+        complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
         "R_TOC",               /* name */                                 
         true,                  /* partial_inplace */                      
@@ -157,7 +528,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 7 },
+  EMPTY_HOWTO (7),
   
   /* Non modifiable absolute branch.  */
   HOWTO (8,                    /* type */                                 
@@ -174,7 +545,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0x3fffffc,             /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 9 },
+  EMPTY_HOWTO (9),
 
   /* Non modifiable relative branch.  */
   HOWTO (0xa,                  /* type */                                 
@@ -191,7 +562,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0x3fffffc,             /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0xb },
+  EMPTY_HOWTO (0xb),
 
   /* Indirect load.  */
   HOWTO (0xc,                  /* type */                                 
@@ -223,7 +594,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0xe },
+  EMPTY_HOWTO (0xe),
   
   /* Non-relocating reference.  */
   HOWTO (0xf,                  /* type */                                 
@@ -240,8 +611,8 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0x10 },
-  { 0x11 },
+  EMPTY_HOWTO (0x10),
+  EMPTY_HOWTO (0x11),
   
   /* TOC relative indirect load.  */
   HOWTO (0x12,                 /* type */                                 
@@ -327,7 +698,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_CREL",              /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
@@ -372,7 +743,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_signed, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_RBR",               /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
@@ -387,30 +758,93 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_RBRC",              /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
+        false),                /* pcrel_offset */
+  HOWTO (0,                     /* type */
+         0,                     /* rightshift */
+         4,                     /* size (0 = byte, 1 = short, 2 = long) */
+         64,                    /* bitsize */
+         false,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_bitfield, /* complain_on_overflow */
+         0,                     /* special_function */
+         "R_POS",               /* name */
+         true,                  /* partial_inplace */
+         MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
         false)                 /* pcrel_offset */
+
 };
 
-#define RTYPE2HOWTO(cache_ptr, dst) rs6000coff_rtype2howto (cache_ptr, dst)
+/* These are the first two like the above but for 16-bit relocs.  */
+static reloc_howto_type xcoff_howto_table_16[] =
+{
+  /* Standard 16 bit relocation.  */
+  HOWTO (0,                    /* type */                                 
+        0,                     /* rightshift */                           
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        16,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_POS_16",            /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false),                /* pcrel_offset */
 
-static void rs6000coff_rtype2howto PARAMS ((arelent *,
-                                           struct internal_reloc *));
+  /* 16 bit relocation, but store negative value.  */
+  HOWTO (1,                    /* type */                                 
+        0,                     /* rightshift */                           
+        -2,                    /* size (0 = byte, 1 = short, 2 = long) */ 
+        16,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_NEG_16",            /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false),                /* pcrel_offset */
 
-static void
-rs6000coff_rtype2howto (relent, internal)
+  /* 16 bit PC relative relocation.  */
+  HOWTO (2,                    /* type */                                 
+        0,                     /* rightshift */                           
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        32,                    /* bitsize */                   
+        true,                  /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_signed, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_REL_16",            /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false)                /* pcrel_offset */
+  };
+  
+void
+_bfd_xcoff_rtype2howto (relent, internal)
      arelent *relent;
      struct internal_reloc *internal;
 {
-  relent->howto = rs6000coff_howto_table + internal->r_type;
+  relent->howto = xcoff_howto_table + internal->r_type;
+
+  if (relent->howto->bitsize != ((unsigned int) internal->r_size & 0x1f) + 1
+      && (internal->r_type 
+         < sizeof(xcoff_howto_table_16)/sizeof(xcoff_howto_table_16[0])))
+    relent->howto = xcoff_howto_table_16 + internal->r_type;
 
   /* The r_size field of an XCOFF reloc encodes the bitsize of the
      relocation, as well as indicating whether it is signed or not.
      Doublecheck that the relocation information gathered from the
      type matches this information.  */
-  if (relent->howto->bitsize != (internal->r_size & 0x1f) + 1)
+  if (relent->howto->bitsize != ((unsigned int) internal->r_size & 0x1f) + 1)
     abort ();
 #if 0
   if ((internal->r_size & 0x80) != 0
@@ -420,367 +854,1408 @@ rs6000coff_rtype2howto (relent, internal)
 #endif
 }
 
-#define coff_bfd_reloc_type_lookup rs6000coff_reloc_type_lookup
-
-static const struct reloc_howto_struct *rs6000coff_reloc_type_lookup
-  PARAMS ((bfd *, bfd_reloc_code_real_type));
-
-static const struct reloc_howto_struct *
-rs6000coff_reloc_type_lookup (abfd, code)
-     bfd *abfd;
+reloc_howto_type *
+_bfd_xcoff_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type code;
 {
   switch (code)
     {
     case BFD_RELOC_PPC_B26:
-      return &rs6000coff_howto_table[0xa];
+      return &xcoff_howto_table[0xa];
     case BFD_RELOC_PPC_BA26:
-      return &rs6000coff_howto_table[8];
+      return &xcoff_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
-      return &rs6000coff_howto_table[3];
+      return &xcoff_howto_table[3];
     case BFD_RELOC_32:
-      return &rs6000coff_howto_table[0];
+    case BFD_RELOC_CTOR:
+      return &xcoff_howto_table[0];
+    case BFD_RELOC_64:
+      return &xcoff_howto_table[0x1c];
     default:
       return NULL;
     }
 }
 
-#define SELECT_RELOC(internal, howto)                                  \
-  {                                                                    \
-    internal.r_type = howto->type;                                     \
-    internal.r_size =                                                  \
-      ((howto->complain_on_overflow == complain_overflow_signed                \
-       ? 0x80                                                          \
-       : 0)                                                            \
-       | (howto->bitsize - 1));                                                \
-  }
+\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.
+
+   AIX 4.3 introduced a new archive format which can handle larger
+   files and also 32- and 64-bit objects in the same archive.  The
+   things said above remain true except that there is now more than
+   one global symbol table.  The one is used to index 32-bit objects,
+   the other for 64-bit objects.
+
+   The new archives (recognizable by the new ARMAG string) has larger
+   field lengths so that we cannot really share any code.  Also we have
+   to take care that we are not generating the new form of archives
+   on AIX 4.2 or earlier systems.  */
+
+/* XCOFF archives use this as a magic string.  Note that both strings
+   have the same length.  */
+
+#define XCOFFARMAG    "<aiaff>\012"
+#define XCOFFARMAGBIG "<bigaf>\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];
 
-#define COFF_LONG_FILENAMES
+  /* Offset of the member table (decimal ASCII string).  */
+  char memoff[12];
 
-#include "coffcode.h"
+  /* Offset of the global symbol table (decimal ASCII string).  */
+  char symoff[12];
 
-#define        coff_archive_p          bfd_generic_archive_p
-#define        coff_mkarchive          _bfd_generic_mkarchive
+  /* Offset of the first member in the archive (decimal ASCII string).  */
+  char firstmemoff[12];
 
-#ifdef HOST_AIX
+  /* Offset of the last member in the archive (decimal ASCII string).  */
+  char lastmemoff[12];
 
-/* ------------------------------------------------------------------------ */
-/*     Support for archive file stuff..                                    */
-/*     Stolen from Damon A. Permezel's `bfd' portation.                    */
-/* ------------------------------------------------------------------------ */
+  /* Offset of the first member on the free list (decimal ASCII
+     string).  */
+  char freeoff[12];
+};
 
-#undef coff_openr_next_archived_file
-#define coff_openr_next_archived_file  rs6000coff_openr_next_archived_file
+#define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG)
 
-#undef coff_write_armap
-#define coff_write_armap               rs6000coff_write_armap
+/* This is the equivalent data structure for the big archive format.  */
 
-#undef coff_stat_arch_elt
-#define        coff_stat_arch_elt              rs6000coff_stat_arch_elt
+struct xcoff_ar_file_hdr_big
+{
+  /* Magic string.  */
+  char magic[SXCOFFARMAG];
 
-#undef coff_snarf_ar_hdr
-#define        coff_snarf_ar_hdr               rs6000coff_snarf_ar_hdr
+  /* Offset of the member table (decimal ASCII string).  */
+  char memoff[20];
 
-#undef coff_mkarchive
-#define        coff_mkarchive                  rs6000coff_mkarchive
+  /* Offset of the global symbol table for 32-bit objects (decimal ASCII
+     string).  */
+  char symoff[20];
 
-#undef coff_archive_p
-#define        coff_archive_p                  rs6000coff_archive_p
+  /* Offset of the global symbol table for 64-bit objects (decimal ASCII
+     string).  */
+  char symoff64[20];
 
-#include "/usr/include/ar.h"           /* <ar.h> doesn't do it.        */
+  /* Offset of the first member in the archive (decimal ASCII string).  */
+  char firstmemoff[20];
 
+  /* Offset of the last member in the archive (decimal ASCII string).  */
+  char lastmemoff[20];
 
-#define arch_hdr(bfd)          \
-       ((struct ar_hdr *)      \
-        (((struct areltdata *)((bfd)->arelt_data))->arch_header))
+  /* Offset of the first member on the free list (decimal ASCII
+     string).  */
+  char freeoff[20];
+};
 
+#define SIZEOF_AR_FILE_HDR_BIG (6 * 20 + SXCOFFARMAG)
 
-static boolean
-rs6000coff_mkarchive (abfd)
-     bfd *abfd;
+
+/* Each XCOFF archive member starts with this (printable) structure.  */
+
+struct xcoff_ar_hdr
 {
-       bfd_error = invalid_operation;  /* write not supported  */
-       return false;
-}
+  /* 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];
 
-/* This functions reads an arch header and returns an areltdata pointer, or
-   NULL on error.
+  /* 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.  */
+};
 
-   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.
-*/
+#define SIZEOF_AR_HDR (7 * 12 + 4)
 
-struct areltdata *
-rs6000coff_snarf_ar_hdr (abfd)
+/* The equivalent for the big archive format.  */
+
+struct xcoff_ar_hdr_big
+{
+  /* File size not including the header (decimal ASCII string).  */
+  char size[20];
+
+  /* File offset of next archive member (decimal ASCII string).  */
+  char nextoff[20];
+
+  /* File offset of previous archive member (decimal ASCII string).  */
+  char prevoff[20];
+
+  /* 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.  */
+};
+
+#define SIZEOF_AR_HDR_BIG (3 * 20 + 4 * 12 + 4)
+
+
+/* We often have to distinguish between the old and big file format.
+   Make it a bit cleaner.  We can use `xcoff_ardata' here because the
+   `hdr' member has the same size and position in both formats.  */
+#define xcoff_big_format_p(abfd) \
+  (xcoff_ardata (abfd)->magic[1] == 'b')
+
+/* We store a copy of the xcoff_ar_file_hdr in the tdata field of the
+   artdata structure.  Similar for the big archive.  */
+#define xcoff_ardata(abfd) \
+  ((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata)
+#define xcoff_ardata_big(abfd) \
+  ((struct xcoff_ar_file_hdr_big *) bfd_ardata (abfd)->tdata)
+
+/* We store a copy of the xcoff_ar_hdr in the arelt_data field of an
+   archive element.  Similar for the big archive.  */
+#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
+#define arch_xhdr(bfd) \
+  ((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header)
+#define arch_xhdr_big(bfd) \
+  ((struct xcoff_ar_hdr_big *) arch_eltdata (bfd)->arch_header)
+
+/* Read in the armap of an XCOFF archive.  */
+
+boolean
+_bfd_xcoff_slurp_armap (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) {
-               bfd_error = no_more_archived_files;
-               return NULL;
+  file_ptr off;
+  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;
+    }
+
+  if (! xcoff_big_format_p (abfd))
+    {
+      /* This is for the old format.  */
+      struct xcoff_ar_hdr hdr;
+
+      off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10);
+      if (off == 0)
+       {
+         bfd_has_map (abfd) = false;
+         return true;
        }
-       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 (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;
+
+      sz = strtol (hdr.size, (char **) NULL, 10);
+    }
+  else
+    {
+      /* This is for the new format.  */
+      struct xcoff_ar_hdr_big hdr;
+
+      off = strtol (xcoff_ardata_big (abfd)->symoff, (char **) NULL, 10);
+      if (off == 0)
+       {
+         bfd_has_map (abfd) = false;
+         return true;
        }
 
-       if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
-               bfd_error = malformed_archive;
-               return NULL;
+      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_BIG, 1, abfd)
+         != SIZEOF_AR_HDR_BIG)
+       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;
+
+      /* XXX This actually has to be a call to strtoll (at least on 32-bit
+        machines) since the field width is 20 and there numbers with more
+        than 32 bits can be represented.  */
+      sz = strtol (hdr.size, (char **) NULL, 10);
+    }
+
+  /* Read in the entire symbol table.  */
+  contents = (bfd_byte *) bfd_alloc (abfd, sz);
+  if (contents == NULL)
+    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)
+    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;
+
+  return true;
+}
 
-       h.hdr._ar_name.ar_name[size] = 0;       /* terminate filename   */
+/* See if this is an XCOFF archive.  */
 
-       /*
-        * if the filename is NULL, we're (probably) at the end.
-        */
-       if (size == 0) {
-               bfd_error = no_more_archived_files;
-               return NULL;
+const bfd_target *
+_bfd_xcoff_archive_p (abfd)
+     bfd *abfd;
+{
+  char magic[SXCOFFARMAG];
+
+  if (bfd_read ((PTR) magic, SXCOFFARMAG, 1, abfd) != SXCOFFARMAG)
+    {
+      if (bfd_get_error () != bfd_error_system_call)
+       bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  if (strncmp (magic, XCOFFARMAG, SXCOFFARMAG) != 0
+      && strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  /* 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 (bfd_ardata (abfd) == (struct artdata *) NULL)
+    return NULL;
+
+  bfd_ardata (abfd)->cache = NULL;
+  bfd_ardata (abfd)->archive_head = NULL;
+  bfd_ardata (abfd)->symdefs = NULL;
+  bfd_ardata (abfd)->extended_names = NULL;
+
+  /* Now handle the two formats.  */
+  if (magic[1] != 'b')
+    {
+      /* This is the old format.  */
+      struct xcoff_ar_file_hdr hdr;
+
+      /* Copy over the magic string.  */
+      memcpy (hdr.magic, magic, SXCOFFARMAG);
+
+      /* Now read the rest of the file header.  */
+      if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR - SXCOFFARMAG, 1,
+                   abfd) != SIZEOF_AR_FILE_HDR - SXCOFFARMAG)
+       {
+         if (bfd_get_error () != bfd_error_system_call)
+           bfd_set_error (bfd_error_wrong_format);
+         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)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR);
+      if (bfd_ardata (abfd)->tdata == NULL)
+       return NULL;
 
-       if (allocptr == NULL) {
-               bfd_error = no_memory;
-               return NULL;
+      memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
+    }
+  else
+    {
+      /* This is the new format.  */
+      struct xcoff_ar_file_hdr_big hdr;
+
+      /* Copy over the magic string.  */
+      memcpy (hdr.magic, magic, SXCOFFARMAG);
+
+      /* Now read the rest of the file header.  */
+      if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG, 1,
+                   abfd) != SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG)
+       {
+         if (bfd_get_error () != bfd_error_system_call)
+           bfd_set_error (bfd_error_wrong_format);
+         return NULL;
        }
 
-       ared = (struct areltdata *) allocptr;
+      /* XXX This actually has to be a call to strtoll (at least on 32-bit
+        machines) since the field width is 20 and there numbers with more
+        than 32 bits can be represented.  */
+      bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
+                                                     (char **) NULL, 10);
 
-       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;
+      bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR_BIG);
+      if (bfd_ardata (abfd)->tdata == NULL)
+       return NULL;
 
-       return ared;
+      memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG);
+    }
+
+  if (! _bfd_xcoff_slurp_armap (abfd))
+    {
+      bfd_release (abfd, bfd_ardata (abfd));
+      abfd->tdata.aout_ar_data = (struct artdata *) NULL;
+      return NULL;
+    }
+
+  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;
+PTR
+_bfd_xcoff_read_ar_hdr (abfd)
+     bfd *abfd;
 {
-  struct areltdata *new_areldata;
-  bfd *n_nfd;
+  size_t namlen;
+  struct areltdata *ret;
 
-  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;
+  ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata));
+  if (ret == NULL)
     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);
+  if (! xcoff_big_format_p (abfd))
+    {
+      struct xcoff_ar_hdr hdr;
+      struct xcoff_ar_hdr *hdrp;
+
+      if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
+       {
+         free (ret);
+         return NULL;
+       }
+
+      namlen = strtol (hdr.namlen, (char **) NULL, 10);
+      hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd,
+                                               SIZEOF_AR_HDR + namlen + 1);
+      if (hdrp == NULL)
+       {
+         free (ret);
+         return NULL;
+       }
+      memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
+      if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen)
+       {
+         free (ret);
+         return NULL;
+       }
+      ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0';
+
+      ret->arch_header = (char *) hdrp;
+      ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
+      ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
+    }
+  else
+    {
+      struct xcoff_ar_hdr_big hdr;
+      struct xcoff_ar_hdr_big *hdrp;
+
+      if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd)
+         != SIZEOF_AR_HDR_BIG)
+       {
+         free (ret);
+         return NULL;
+       }
+
+      namlen = strtol (hdr.namlen, (char **) NULL, 10);
+      hdrp = (struct xcoff_ar_hdr_big *) bfd_alloc (abfd,
+                                                   SIZEOF_AR_HDR_BIG
+                                                   + namlen + 1);
+      if (hdrp == NULL)
+       {
+         free (ret);
+         return NULL;
+       }
+      memcpy (hdrp, &hdr, SIZEOF_AR_HDR_BIG);
+      if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR_BIG, 1, namlen, abfd) != namlen)
+       {
+         free (ret);
+         return NULL;
+       }
+      ((char *) hdrp)[SIZEOF_AR_HDR_BIG + namlen] = '\0';
+
+      ret->arch_header = (char *) hdrp;
+      /* XXX This actually has to be a call to strtoll (at least on 32-bit
+        machines) since the field width is 20 and there numbers with more
+        than 32 bits can be represented.  */
+      ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
+      ret->filename = (char *) hdrp + SIZEOF_AR_HDR_BIG;
+    }
+
+  /* Skip over the XCOFFARFMAG at the end of the file name.  */
+  if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0)
     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;
+  return (PTR) ret;
+}
+
+/* Open the next element in an XCOFF archive.  */
+
+bfd *
+_bfd_xcoff_openr_next_archived_file (archive, last_file)
+     bfd *archive;
+     bfd *last_file;
+{
+  file_ptr filestart;
 
-  /* huh? */
-  bfd_release (archive, (PTR)n_nfd);
-  bfd_release (archive, (PTR)new_areldata);
-  return NULL;
+  if (xcoff_ardata (archive) == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return NULL;
+    }
+
+  if (! xcoff_big_format_p (archive))
+    {
+      if (last_file == NULL)
+       filestart = bfd_ardata (archive)->first_file_filepos;
+      else
+       filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL,
+                           10);
+
+      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;
+       }
+    }
+  else
+    {
+      if (last_file == NULL)
+       filestart = bfd_ardata (archive)->first_file_filepos;
+      else
+       /* XXX These actually have to be a calls to strtoll (at least
+          on 32-bit machines) since the fields's width is 20 and
+          there numbers with more than 32 bits can be represented.  */
+       filestart = strtol (arch_xhdr_big (last_file)->nextoff, (char **) NULL,
+                           10);
+
+      /* XXX These actually have to be calls to strtoll (at least on 32-bit
+        machines) since the fields's width is 20 and there numbers with more
+        than 32 bits can be represented.  */
+      if (filestart == 0
+         || filestart == strtol (xcoff_ardata_big (archive)->memoff,
+                                 (char **) NULL, 10)
+         || filestart == strtol (xcoff_ardata_big (archive)->symoff,
+                                 (char **) NULL, 10))
+       {
+         bfd_set_error (bfd_error_no_more_archived_files);
+         return NULL;
+       }
+    }
+
+  return _bfd_get_elt_at_filepos (archive, filestart);
 }
 
-/*
- * 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; 
+/* Stat an element in an XCOFF archive.  */
+
+int
+_bfd_xcoff_generic_stat_arch_elt (abfd, s)
+     bfd *abfd;
+     struct stat *s;
 {
-       file_ptr filestart;
+  if (abfd->arelt_data == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  if (! xcoff_big_format_p (abfd))
+    {
+      struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd);
+
+      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;
+    }
+  else
+    {
+      struct xcoff_ar_hdr_big *hdrp = arch_xhdr_big (abfd);
 
-       if (!last_file)
-               filestart = bfd_ardata(archive)->first_file_filepos;
-       else
-               filestart = atol(arch_hdr(last_file)->ar_nxtmem);
+      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;
+    }
 
-       return rs6000coff_get_elt_at_filepos (archive, filestart);
+  return 0;
 }
 
+/* Normalize a file name for inclusion in an archive.  */
 
-static bfd_target *
-rs6000coff_archive_p (abfd)
+static const char *
+normalize_filename (abfd)
      bfd *abfd;
 {
-       struct fl_hdr hdr;
-       register struct artdata *art;
+  const char *file;
+  const char *filename;
+
+  file = bfd_get_filename (abfd);
+  filename = strrchr (file, '/');
+  if (filename != NULL)
+    filename++;
+  else
+    filename = file;
+  return filename;
+}
 
-       if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) {
-               bfd_error = wrong_format;
-               return 0;
-       }
+/* Write out an XCOFF armap.  */
 
-       if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
-               bfd_error = wrong_format;
-               return 0;
+/*ARGSUSED*/
+static boolean
+xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
+     bfd *abfd;
+     unsigned int elength ATTRIBUTE_UNUSED;
+     struct orl *map;
+     unsigned int orl_count;
+     int stridx;
+{
+  struct xcoff_ar_hdr hdr;
+  char *p;
+  unsigned 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;
+
+  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;
        }
+      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;
+    }
+
+  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;
+    }
 
-       /*
-        * 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_error = no_memory;
-               return 0;
+  return true;
+}
+
+/*ARGSUSED*/
+static boolean
+xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
+     bfd *abfd;
+     unsigned int elength ATTRIBUTE_UNUSED;
+     struct orl *map;
+     unsigned int orl_count;
+     int stridx;
+{
+  struct xcoff_ar_hdr_big hdr;
+  char *p;
+  unsigned char buf[4];
+  bfd *sub;
+  file_ptr fileoff;
+  unsigned int i;
+
+  memset (&hdr, 0, sizeof hdr);
+  /* XXX This call actually should use %lld (at least on 32-bit
+     machines) since the fields's width is 20 and there numbers with
+     more than 32 bits can be represented.  */
+  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_BIG; p++)
+    if (*p == '\0')
+      *p = ' ';
+
+  if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd) != SIZEOF_AR_HDR_BIG
+      || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG)
+    return false;
+
+  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_BIG;
+  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;
        }
+      namlen = strlen (normalize_filename (sub));
+      namlen = (namlen + 1) &~ 1;
+      fileoff += (SIZEOF_AR_HDR_BIG
+                 + namlen
+                 + SXCOFFARFMAG
+                 + arelt_size (sub));
+      fileoff = (fileoff + 1) &~ 1;
+      sub = sub->next;
+    }
 
-       art->first_file_filepos = atoi(hdr.fl_fstmoff);
-       *(struct fl_hdr *) (1 + art) = hdr;
+  for (i = 0; i < orl_count; i++)
+    {
+      const char *name;
+      size_t namlen;
 
-       /* Someday...
-        * slurp in the member table, which I think is the armap equivalent.
-       xcoff_slurp_armap(abfd);
-        */
-  
-       return abfd->xvec;
+      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;
 }
 
+/*ARGSUSED*/
+boolean
+_bfd_xcoff_write_armap (abfd, elength, map, orl_count, stridx)
+     bfd *abfd;
+     unsigned int elength ATTRIBUTE_UNUSED;
+     struct orl *map;
+     unsigned int orl_count;
+     int stridx;
+{
+  if (! xcoff_big_format_p (abfd))
+    return xcoff_write_armap_old (abfd, elength, map, orl_count, stridx);
+  else
+    return xcoff_write_armap_big (abfd, elength, map, orl_count, stridx);
+}
+
+/* Write out an XCOFF archive.  We always write an entire archive,
+   rather than fussing with the freelist and so forth.  */
 
-static int
-rs6000coff_stat_arch_elt(abfd, buf)
-  bfd *abfd;
-  struct stat *buf;
+static boolean
+xcoff_write_archive_contents_old (abfd)
+     bfd *abfd;
 {
-       struct ar_hdr *hdr;
-       char *aloser;
-  
-       if (abfd->arelt_data == NULL) {
-               bfd_error = invalid_operation;
-               return -1;
+  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)
+    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;
        }
-    
-       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
-
-       return 0;
+      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 false;
+           }
+
+         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 = bfd_alloc (sub, sizeof (struct areltdata));
+             if (sub->arelt_data == NULL)
+               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;
+
+      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;
 }
 
 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_big (abfd)
+     bfd *abfd;
 {
-       bfd_error = invalid_operation;
+  struct xcoff_ar_file_hdr_big 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_big ahdr;
+  bfd_size_type size;
+  char *p;
+  char decbuf[13];
+
+  memset (&fhdr, 0, sizeof fhdr);
+  strncpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
+  sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR_BIG);
+  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)
+    return false;
+
+  if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0)
+    return false;
+
+  makemap = bfd_has_map (abfd);
+  hasobjects = false;
+  prevoff = 0;
+  nextoff = SIZEOF_AR_FILE_HDR_BIG;
+  for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++)
+    {
+      const char *name;
+      size_t namlen;
+      struct xcoff_ar_hdr_big *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_big (sub);
+      else
+       ahdrp = NULL;
+
+      if (ahdrp == NULL)
+       {
+         struct stat s;
+
+         memset (&ahdr, 0, sizeof ahdr);
+         ahdrp = &ahdr;
+         /* XXX This should actually be a call to stat64 (at least on
+            32-bit machines).  */
+         if (stat (bfd_get_filename (sub), &s) != 0)
+           {
+             bfd_set_error (bfd_error_system_call);
+             return false;
+           }
+
+         /* XXX This call actually should use %lld (at least on 32-bit
+            machines) since the fields's width is 20 and there numbers with
+            more than 32 bits can be represented.  */
+         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 = bfd_alloc (sub, sizeof (struct areltdata));
+             if (sub->arelt_data == NULL)
+               return false;
+           }
+
+         arch_eltdata (sub)->parsed_size = s.st_size;
+       }
+
+      /* XXX These calls actually should use %lld (at least on 32-bit
+        machines) since the fields's width is 20 and there numbers with
+        more than 32 bits can be represented.  */
+      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_BIG
+             + 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_BIG; p++)
+       if (*p == '\0')
+         *p = ' ';
+
+      if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR_BIG, abfd)
+         != SIZEOF_AR_HDR_BIG
+         || bfd_write ((PTR) name, 1, namlen, abfd) != namlen
+         || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd)
+             != SXCOFFARFMAG))
        return false;
-}
-#endif /* HOST_AIX */
 
-\f
-#define CORE_FILE_P _bfd_dummy_target
+      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;
 
-#ifdef HOST_AIX
-#undef CORE_FILE_P
-#define CORE_FILE_P rs6000coff_core_p
-extern bfd_target * rs6000coff_core_p ();
-extern boolean rs6000coff_get_section_contents ();
-extern boolean rs6000coff_core_file_matches_executable_p ();
+         b = '\0';
+         if (bfd_write (&b, 1, 1, abfd) != 1)
+           return false;
+       }
+    }
 
-#undef coff_core_file_matches_executable_p
-#define coff_core_file_matches_executable_p  \
-                                    rs6000coff_core_file_matches_executable_p
+  /* XXX This call actually should use %lld (at least on 32-bit
+     machines) since the fields's width is 20 and there numbers with
+     more than 32 bits can be represented.  */
+  sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
+
+  /* Write out the member table.  */
+
+  BFD_ASSERT (nextoff == bfd_tell (abfd));
+  /* XXX This call actually should use %lld (at least on 32-bit
+     machines) since the fields's width is 20 and there numbers with
+     more than 32 bits can be represented.  */
+  sprintf (fhdr.memoff, "%ld", (long) nextoff);
+
+  memset (&ahdr, 0, sizeof ahdr);
+  /* XXX The next two calls actually should use %lld (at least on 32-bit
+     machines) since the fields's width is 20 and there numbers with
+     more than 32 bits can be represented.  */
+  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_BIG
+         + 12
+         + count * 12
+         + total_namlen
+         + SXCOFFARFMAG);
+
+  prevoff = nextoff;
+  nextoff += size + (size & 1);
+
+  if (makemap && hasobjects)
+    /* XXX This call actually should use %lld (at least on 32-bit
+       machines) since the fields's width is 20 and there numbers with
+       more than 32 bits can be represented.  */
+    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_BIG; p++)
+    if (*p == '\0')
+      *p = ' ';
+
+  if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG
+      || (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;
 
-#undef coff_get_section_contents
-#define        coff_get_section_contents       rs6000coff_get_section_contents
-#endif /* HOST_AIX */
+      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;
 
-#ifdef HOST_LYNX
+      b = '\0';
+      if (bfd_write ((PTR) &b, 1, 1, abfd) != 1)
+       return false;
+    }
 
-#undef CORE_FILE_P
-#define CORE_FILE_P lynx_core_file_p
-extern bfd_target *lynx_core_file_p PARAMS ((bfd *abfd));
+  /* Write out the armap, if appropriate.  */
 
-extern boolean lynx_core_file_matches_executable_p PARAMS ((bfd *core_bfd,
-                                                           bfd *exec_bfd));
-#undef coff_core_file_matches_executable_p
-#define coff_core_file_matches_executable_p lynx_core_file_matches_executable_p
+  if (! makemap || ! hasobjects)
+    sprintf (fhdr.symoff, "%d", 0);
+  else
+    {
+      BFD_ASSERT (nextoff == bfd_tell (abfd));
+      /* XXX This call actually should use %lld (at least on 32-bit
+        machines) since the fields's width is 20 and there numbers with
+        more than 32 bits can be represented.  */
+      sprintf (fhdr.symoff, "%ld", (long) nextoff);
+      bfd_ardata (abfd)->tdata = (PTR) &fhdr;
+      if (! _bfd_compute_and_write_armap (abfd, 0))
+       return false;
+    }
 
-extern char *lynx_core_file_failing_command PARAMS ((bfd *abfd));
-#undef coff_core_file_failing_command
-#define coff_core_file_failing_command lynx_core_file_failing_command
+  /* Write out the archive file header.  */
 
-extern int lynx_core_file_failing_signal PARAMS ((bfd *abfd));
-#undef coff_core_file_failing_signal
-#define coff_core_file_failing_signal lynx_core_file_failing_signal
+  /* We need spaces, not null bytes, in the header.  */
+  for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR_BIG; p++)
+    if (*p == '\0')
+      *p = ' ';
 
-#endif /* HOST_LYNX */
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+      || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR_BIG, 1, abfd) !=
+         SIZEOF_AR_FILE_HDR_BIG))
+    return false;
 
-/* The transfer vector that leads the outside world to all of the above. */
+  return true;
+}
 
-bfd_target rs6000coff_vec =
+boolean
+_bfd_xcoff_write_archive_contents (abfd)
+     bfd *abfd;
 {
-  "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, CORE_FILE_P},
-  {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,
-};
+  if (! xcoff_big_format_p (abfd))
+    return xcoff_write_archive_contents_old (abfd);
+  else
+    return xcoff_write_archive_contents_big (abfd);
+}
+\f
+/* We can't use the usual coff_sizeof_headers routine, because AIX
+   always uses an a.out header.  */
+
+/*ARGSUSED*/
+int
+_bfd_xcoff_sizeof_headers (abfd, reloc)
+     bfd *abfd;
+     boolean reloc ATTRIBUTE_UNUSED;
+{
+  int size;
+
+  size = FILHSZ;
+  if (xcoff_data (abfd)->full_aouthdr)
+    size += AOUTSZ;
+  else
+    size += SMALL_AOUTSZ;
+  size += abfd->section_count * SCNHSZ;
+  return size;
+}
+\f
+