OSDN Git Service

bfd/
authorrsandifo <rsandifo>
Wed, 1 Apr 2009 20:04:28 +0000 (20:04 +0000)
committerrsandifo <rsandifo>
Wed, 1 Apr 2009 20:04:28 +0000 (20:04 +0000)
* coff-rs6000.c (member_layout): New structure.
(archive_iterator): Likewise.
(member_layout_init): New function.
(archive_iterator_begin): Likewise.
(archive_iterator_next): Likewise.
(xcoff_write_armap_old): Use the new iterator functions.
(do_shared_object_padding): Delete.
(xcoff_write_armap_big): Use the new iterator functions.  Simplify
handling of arch_info.
(xcoff_write_archive_contents_old): Allocate arelt_data in the
first loop rather than the second.  Allocate a member header if
there isn't one, then work out the stat information and length
in the first loop too.  Use the new iterators for the second loop.
(xcoff_write_archive_contents_big): Likewise.

bfd/ChangeLog
bfd/coff-rs6000.c

index 54f37ab..6d3b405 100644 (file)
@@ -1,5 +1,22 @@
 2009-04-01  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
+       * coff-rs6000.c (member_layout): New structure.
+       (archive_iterator): Likewise.
+       (member_layout_init): New function.
+       (archive_iterator_begin): Likewise.
+       (archive_iterator_next): Likewise.
+       (xcoff_write_armap_old): Use the new iterator functions.
+       (do_shared_object_padding): Delete.
+       (xcoff_write_armap_big): Use the new iterator functions.  Simplify
+       handling of arch_info.
+       (xcoff_write_archive_contents_old): Allocate arelt_data in the
+       first loop rather than the second.  Allocate a member header if
+       there isn't one, then work out the stat information and length
+       in the first loop too.  Use the new iterators for the second loop.
+       (xcoff_write_archive_contents_big): Likewise.
+
+2009-04-01  Richard Sandiford  <r.sandiford@uk.ibm.com>
+
        * bfd-in.h (bfd_xcoff_split_import_path): Declare.
        (bfd_xcoff_set_archive_import_path): Likewise.
        * bfd-in2.h: Regenerate.
index 3343530..c5a486b 100644 (file)
@@ -180,8 +180,6 @@ static bfd_boolean do_pad
   PARAMS ((bfd *, unsigned int));
 static bfd_boolean do_copy
   PARAMS ((bfd *, bfd *));
-static bfd_boolean do_shared_object_padding
-  PARAMS ((bfd *, bfd *, file_ptr *, int));
 
 /* Relocation functions */
 static bfd_boolean xcoff_reloc_type_br
@@ -238,6 +236,119 @@ bfd_boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW])
   xcoff_complain_overflow_unsigned_func,
 };
 
+/* Information about one member of an archive.  */
+struct member_layout {
+  /* The archive member that this structure describes.  */
+  bfd *member;
+
+  /* The number of bytes of padding that must be inserted before the
+     start of the member in order to ensure that the section contents
+     are correctly aligned.  */
+  unsigned int leading_padding;
+
+  /* The offset of MEMBER from the start of the archive (i.e. the end
+     of the leading padding).  */
+  file_ptr offset;
+
+  /* The normalized name of MEMBER.  */
+  const char *name;
+
+  /* The length of NAME, without padding.  */
+  bfd_size_type namlen;
+
+  /* The length of NAME, with padding.  */
+  bfd_size_type padded_namlen;
+
+  /* The size of MEMBER's header, including the name and magic sequence.  */
+  bfd_size_type header_size;
+
+  /* The size of the MEMBER's contents.  */
+  bfd_size_type contents_size;
+
+  /* The number of bytes of padding that must be inserted after MEMBER
+     in order to preserve even alignment.  */
+  bfd_size_type trailing_padding;
+};
+
+/* A structure used for iterating over the members of an archive.  */
+struct archive_iterator {
+  /* The archive itself.  */
+  bfd *archive;
+
+  /* Information about the current archive member.  */
+  struct member_layout current;
+
+  /* Information about the next archive member.  MEMBER is null if there
+     are no more archive members, in which case OFFSET is the offset of
+     the first unused byte.  */
+  struct member_layout next;
+};
+
+/* Initialize INFO so that it describes member MEMBER of archive ARCHIVE.
+   OFFSET is the even-padded offset of MEMBER, not including any leading
+   padding needed for section alignment.  */
+
+static void
+member_layout_init (struct member_layout *info, bfd *archive,
+                   bfd *member, file_ptr offset)
+{
+  info->member = member;
+  info->leading_padding = 0;
+  if (member)
+    {
+      info->name = normalize_filename (member);
+      info->namlen = strlen (info->name);
+      info->padded_namlen = info->namlen + (info->namlen & 1);
+      if (xcoff_big_format_p (archive))
+       info->header_size = SIZEOF_AR_HDR_BIG;
+      else
+       info->header_size = SIZEOF_AR_HDR;
+      info->header_size += info->padded_namlen + SXCOFFARFMAG;
+      info->contents_size = arelt_size (member);
+      info->trailing_padding = info->contents_size & 1;
+
+      if (bfd_check_format (member, bfd_object)
+         && bfd_get_flavour (member) == bfd_target_xcoff_flavour
+         && (member->flags & DYNAMIC) != 0)
+       info->leading_padding
+         = (-(offset + info->header_size)
+            & ((1 << bfd_xcoff_text_align_power (member)) - 1));
+    }
+  info->offset = offset + info->leading_padding;
+}
+
+/* Set up ITERATOR to iterate through archive ARCHIVE.  */
+
+static void
+archive_iterator_begin (struct archive_iterator *iterator,
+                       bfd *archive)
+{
+  iterator->archive = archive;
+  member_layout_init (&iterator->next, archive, archive->archive_head,
+                     xcoff_big_format_p (archive)
+                     ? SIZEOF_AR_FILE_HDR_BIG
+                     : SIZEOF_AR_FILE_HDR);
+}
+
+/* Make ITERATOR visit the first unvisited archive member.  Return true
+   on success; return false if all members have been visited.  */
+
+static bfd_boolean
+archive_iterator_next (struct archive_iterator *iterator)
+{
+  if (!iterator->next.member)
+    return FALSE;
+
+  iterator->current = iterator->next;
+  member_layout_init (&iterator->next, iterator->archive,
+                     iterator->current.member->archive_next,
+                     iterator->current.offset
+                     + iterator->current.header_size
+                     + iterator->current.contents_size
+                     + iterator->current.trailing_padding);
+  return TRUE;
+}
+
 /* We use our own tdata type.  Its first field is the COFF tdata type,
    so the COFF routines are compatible.  */
 
@@ -1603,11 +1714,10 @@ xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
      unsigned int orl_count;
      int stridx;
 {
+  struct archive_iterator iterator;
   struct xcoff_ar_hdr hdr;
   char *p;
   unsigned char buf[4];
-  bfd *sub;
-  file_ptr fileoff;
   unsigned int i;
 
   memset (&hdr, 0, sizeof hdr);
@@ -1635,29 +1745,16 @@ xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
   if (bfd_bwrite (buf, (bfd_size_type) 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 (map[i].u.abfd == sub)
-       {
-         H_PUT_32 (abfd, fileoff, buf);
-         if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
-           return FALSE;
-         ++i;
-       }
-      namlen = strlen (normalize_filename (sub));
-      namlen = (namlen + 1) &~ (size_t) 1;
-      fileoff += (SIZEOF_AR_HDR
-                 + namlen
-                 + SXCOFFARFMAG
-                 + arelt_size (sub));
-      fileoff = (fileoff + 1) &~ 1;
-      sub = sub->archive_next;
-    }
+  archive_iterator_begin (&iterator, abfd);
+  while (i < orl_count && archive_iterator_next (&iterator))
+    while (map[i].u.abfd == iterator.current.member)
+      {
+       H_PUT_32 (abfd, iterator.current.offset, buf);
+       if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
+         return FALSE;
+       ++i;
+      }
 
   for (i = 0; i < orl_count; i++)
     {
@@ -1759,34 +1856,6 @@ do_copy (out_bfd, in_bfd)
 }
 
 static bfd_boolean
-do_shared_object_padding (out_bfd, in_bfd, offset, ar_header_size)
-     bfd *out_bfd;
-     bfd *in_bfd;
-     file_ptr *offset;
-     int ar_header_size;
-{
-  if (bfd_check_format (in_bfd, bfd_object)
-      && bfd_get_flavour (in_bfd) == bfd_target_xcoff_flavour
-      && (in_bfd->flags & DYNAMIC) != 0)
-    {
-      bfd_size_type pad = 0;
-      int text_align_power;
-
-      text_align_power = bfd_xcoff_text_align_power (in_bfd);
-
-      pad = 1 << text_align_power;
-      pad -= (*offset + ar_header_size) & (pad - 1);
-
-      if (! do_pad (out_bfd, pad))
-       return FALSE;
-
-      *offset += pad;
-    }
-
-  return TRUE;
-}
-
-static bfd_boolean
 xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
      bfd *abfd;
      unsigned int elength ATTRIBUTE_UNUSED;
@@ -1794,9 +1863,10 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
      unsigned int orl_count;
      int stridx;
 {
+  struct archive_iterator iterator;
   struct xcoff_ar_file_hdr_big *fhdr;
   bfd_vma i, sym_32, sym_64, str_32, str_64;
-  const bfd_arch_info_type *arch_info = NULL;
+  const bfd_arch_info_type *arch_info;
   bfd *current_bfd;
   size_t string_length;
   file_ptr nextoff, prevoff;
@@ -1805,16 +1875,15 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
      from 32-bit objects and which from 64-bit ones.  */
   sym_32 = sym_64 = str_32 = str_64 = 0;
 
-  current_bfd = abfd->archive_head;
-  if (current_bfd != NULL)
-    arch_info = bfd_get_arch_info (current_bfd);
-    i = 0;
-    while (current_bfd != NULL && i < orl_count)
+  i = 0;
+  for (current_bfd = abfd->archive_head;
+       current_bfd != NULL && i < orl_count;
+       current_bfd = current_bfd->archive_next)
     {
+      arch_info = bfd_get_arch_info (current_bfd);
       while (map[i].u.abfd == current_bfd)
        {
          string_length = strlen (*map[i].name) + 1;
-
          if (arch_info->bits_per_address == 64)
            {
              sym_64++;
@@ -1827,9 +1896,6 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
            }
          i++;
        }
-      current_bfd = current_bfd->archive_next;
-      if (current_bfd != NULL)
-       arch_info = bfd_get_arch_info (current_bfd);
     }
 
   /* A quick sanity check... */
@@ -1871,7 +1937,6 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
       struct xcoff_ar_hdr_big *hdr;
       char *symbol_table;
       char *st;
-      file_ptr fileoff;
 
       bfd_vma symbol_table_size =
        SIZEOF_AR_HDR_BIG
@@ -1908,41 +1973,29 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
       st += 8;
 
       /* loop over the 32 bit offsets */
-      current_bfd = abfd->archive_head;
-      if (current_bfd != NULL)
-       arch_info = bfd_get_arch_info (current_bfd);
-      fileoff = SIZEOF_AR_FILE_HDR_BIG;
       i = 0;
-      while (current_bfd != NULL && i < orl_count)
+      archive_iterator_begin (&iterator, abfd);
+      while (i < orl_count && archive_iterator_next (&iterator))
        {
-         while (map[i].u.abfd == current_bfd)
+         arch_info = bfd_get_arch_info (iterator.current.member);
+         while (map[i].u.abfd == iterator.current.member)
            {
              if (arch_info->bits_per_address == 32)
                {
-                 bfd_h_put_64 (abfd, fileoff, st);
+                 bfd_h_put_64 (abfd, iterator.current.offset, st);
                  st += 8;
                }
              i++;
            }
-         string_length = strlen (normalize_filename (current_bfd));
-         string_length += string_length & 1;
-         fileoff += (SIZEOF_AR_HDR_BIG
-                     + string_length
-                     + SXCOFFARFMAG
-                     + arelt_size (current_bfd));
-         fileoff += fileoff & 1;
-         current_bfd = current_bfd->archive_next;
-         if (current_bfd != NULL)
-           arch_info = bfd_get_arch_info (current_bfd);
        }
 
       /* loop over the 32 bit symbol names */
-      current_bfd = abfd->archive_head;
-      if (current_bfd != NULL)
-       arch_info = bfd_get_arch_info (current_bfd);
       i = 0;
-      while (current_bfd != NULL && i < orl_count)
+      for (current_bfd = abfd->archive_head;
+          current_bfd != NULL && i < orl_count;
+          current_bfd = current_bfd->archive_next)
        {
+         arch_info = bfd_get_arch_info (current_bfd);
          while (map[i].u.abfd == current_bfd)
            {
              if (arch_info->bits_per_address == 32)
@@ -1952,9 +2005,6 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
                }
              i++;
            }
-         current_bfd = current_bfd->archive_next;
-         if (current_bfd != NULL)
-           arch_info = bfd_get_arch_info (current_bfd);
        }
 
       bfd_bwrite (symbol_table, symbol_table_size, abfd);
@@ -1972,7 +2022,6 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
       struct xcoff_ar_hdr_big *hdr;
       char *symbol_table;
       char *st;
-      file_ptr fileoff;
 
       bfd_vma symbol_table_size =
        SIZEOF_AR_HDR_BIG
@@ -2004,41 +2053,29 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
       st += 8;
 
       /* loop over the 64 bit offsets */
-      current_bfd = abfd->archive_head;
-      if (current_bfd != NULL)
-       arch_info = bfd_get_arch_info (current_bfd);
-      fileoff = SIZEOF_AR_FILE_HDR_BIG;
       i = 0;
-      while (current_bfd != NULL && i < orl_count)
+      archive_iterator_begin (&iterator, abfd);
+      while (i < orl_count && archive_iterator_next (&iterator))
        {
-         while (map[i].u.abfd == current_bfd)
+         arch_info = bfd_get_arch_info (iterator.current.member);
+         while (map[i].u.abfd == iterator.current.member)
            {
              if (arch_info->bits_per_address == 64)
                {
-                 bfd_h_put_64 (abfd, fileoff, st);
+                 bfd_h_put_64 (abfd, iterator.current.offset, st);
                  st += 8;
                }
              i++;
            }
-         string_length = strlen (normalize_filename (current_bfd));
-         string_length += string_length & 1;
-         fileoff += (SIZEOF_AR_HDR_BIG
-                     + string_length
-                     + SXCOFFARFMAG
-                     + arelt_size (current_bfd));
-         fileoff += fileoff & 1;
-         current_bfd = current_bfd->archive_next;
-         if (current_bfd != NULL)
-           arch_info = bfd_get_arch_info (current_bfd);
        }
 
       /* loop over the 64 bit symbol names */
-      current_bfd = abfd->archive_head;
-      if (current_bfd != NULL)
-       arch_info = bfd_get_arch_info (current_bfd);
       i = 0;
-      while (current_bfd != NULL && i < orl_count)
+      for (current_bfd = abfd->archive_head;
+          current_bfd != NULL && i < orl_count;
+          current_bfd = current_bfd->archive_next)
        {
+         arch_info = bfd_get_arch_info (current_bfd);
          while (map[i].u.abfd == current_bfd)
            {
              if (arch_info->bits_per_address == 64)
@@ -2048,9 +2085,6 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
                }
              i++;
            }
-         current_bfd = current_bfd->archive_next;
-         if (current_bfd != NULL)
-           arch_info = bfd_get_arch_info (current_bfd);
        }
 
       bfd_bwrite (symbol_table, symbol_table_size, abfd);
@@ -2086,6 +2120,7 @@ static bfd_boolean
 xcoff_write_archive_contents_old (abfd)
      bfd *abfd;
 {
+  struct archive_iterator iterator;
   struct xcoff_ar_file_hdr fhdr;
   bfd_size_type count;
   bfd_size_type total_namlen;
@@ -2111,118 +2146,92 @@ xcoff_write_archive_contents_old (abfd)
     {
       ++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, (file_ptr) 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->archive_next, i++)
-    {
-      const char *name;
-      bfd_size_type namlen;
-      struct xcoff_ar_hdr *ahdrp;
-      bfd_size_type remaining;
-
-      if (makemap && ! hasobjects)
+      if (sub->arelt_data == NULL)
        {
-         if (bfd_check_format (sub, bfd_object))
-           hasobjects = TRUE;
+         sub->arelt_data = bfd_zalloc (sub, sizeof (struct areltdata));
+         if (sub->arelt_data == NULL)
+           return FALSE;
        }
-
-      name = normalize_filename (sub);
-      namlen = strlen (name);
-
-      if (sub->arelt_data != NULL)
-       ahdrp = arch_xhdr (sub);
-      else
-       ahdrp = NULL;
-
-      if (ahdrp == NULL)
+      if (arch_xhdr (sub) == NULL)
        {
+         struct xcoff_ar_hdr *ahdrp;
          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;
            }
 
+         ahdrp = bfd_zalloc (sub, sizeof (*ahdrp));
+         if (ahdrp == NULL)
+           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)
-           {
-             size = sizeof (struct areltdata);
-             sub->arelt_data = bfd_alloc (sub, size);
-             if (sub->arelt_data == NULL)
-               return FALSE;
-           }
-
+         arch_eltdata (sub)->arch_header = (char *) ahdrp;
          arch_eltdata (sub)->parsed_size = s.st_size;
        }
+    }
+  offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
+  if (offsets == NULL)
+    return FALSE;
 
-      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) &~ (bfd_size_type) 1;
-
-      remaining = arelt_size (sub);
-      size = (SIZEOF_AR_HDR
-             + namlen
-             + SXCOFFARFMAG
-             + remaining);
-
-      BFD_ASSERT (nextoff == bfd_tell (abfd));
+  if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR, SEEK_SET) != 0)
+    return FALSE;
 
-      offsets[i] = nextoff;
+  makemap = bfd_has_map (abfd);
+  hasobjects = FALSE;
+  prevoff = 0;
+  for (archive_iterator_begin (&iterator, abfd), i = 0;
+       archive_iterator_next (&iterator);
+       i++)
+    {
+      bfd_size_type namlen;
+      struct xcoff_ar_hdr *ahdrp;
 
-      prevoff = nextoff;
-      nextoff += size + (size & 1);
+      if (makemap && ! hasobjects)
+       {
+         if (bfd_check_format (iterator.current.member, bfd_object))
+           hasobjects = TRUE;
+       }
 
-      sprintf (ahdrp->nextoff, "%ld", (long) nextoff);
+      ahdrp = arch_xhdr (iterator.current.member);
+      sprintf (ahdrp->prevoff, "%ld", (long) prevoff);
+      sprintf (ahdrp->namlen, "%ld", (long) iterator.current.namlen);
+      sprintf (ahdrp->nextoff, "%ld", (long) iterator.next.offset);
 
       /* 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_bwrite ((PTR) ahdrp, (bfd_size_type) SIZEOF_AR_HDR, abfd)
-          != SIZEOF_AR_HDR)
-         || bfd_bwrite ((PTR) name, namlen, abfd) != namlen
-         || bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG,
-                        abfd) != SXCOFFARFMAG)
-       return FALSE;
-
-      if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
+      if (!do_pad (abfd, iterator.current.leading_padding))
        return FALSE;
 
-      if (! do_copy (abfd, sub))
+      BFD_ASSERT (iterator.current.offset == bfd_tell (abfd));
+      namlen = iterator.current.padded_namlen;
+      if (bfd_bwrite (ahdrp, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR
+         || bfd_bwrite (iterator.current.name, namlen, abfd) != namlen
+         || bfd_bwrite (XCOFFARFMAG, SXCOFFARFMAG, abfd) != SXCOFFARFMAG
+         || bfd_seek (iterator.current.member, 0, SEEK_SET) != 0
+         || !do_copy (abfd, iterator.current.member)
+         || !do_pad (abfd, iterator.current.trailing_padding))
        return FALSE;
 
-      if (! do_pad (abfd, size & 1))
-       return FALSE;
+      offsets[i] = iterator.current.offset;
+      prevoff = iterator.current.offset;
     }
 
   sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
 
   /* Write out the member table.  */
 
+  nextoff = iterator.next.offset;
   BFD_ASSERT (nextoff == bfd_tell (abfd));
   sprintf (fhdr.memoff, "%ld", (long) nextoff);
 
@@ -2327,10 +2336,11 @@ xcoff_write_archive_contents_big (abfd)
   file_ptr prevoff, nextoff;
   bfd *current_bfd;
   size_t i;
-  struct xcoff_ar_hdr_big *hdr, ahdr;
+  struct xcoff_ar_hdr_big *hdr;
   bfd_size_type size;
   char *member_table, *mt;
   bfd_vma member_table_size;
+  struct archive_iterator iterator;
 
   memset (&fhdr, 0, SIZEOF_AR_FILE_HDR_BIG);
   memcpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
@@ -2351,40 +2361,20 @@ xcoff_write_archive_contents_big (abfd)
          && ! hasobjects
          && bfd_check_format (current_bfd, bfd_object))
        hasobjects = TRUE;
-    }
 
-  offsets = NULL;
-  if (count)
-    {
-      offsets = (file_ptr *) bfd_malloc (count * sizeof (file_ptr));
-      if (offsets == NULL)
-       return FALSE;
-    }
-
-  prevoff = 0;
-  nextoff = SIZEOF_AR_FILE_HDR_BIG;
-  for (current_bfd = abfd->archive_head, i = 0;
-       current_bfd != NULL;
-       current_bfd = current_bfd->archive_next, i++)
-    {
-      const char *name;
-      bfd_size_type namlen;
-      struct xcoff_ar_hdr_big *ahdrp;
-      bfd_size_type remaining;
-
-      name = normalize_filename (current_bfd);
-      namlen = strlen (name);
-
-      if (current_bfd->arelt_data != NULL)
-       ahdrp = arch_xhdr_big (current_bfd);
-      else
-       ahdrp = NULL;
+      if (current_bfd->arelt_data == NULL)
+       {
+         size = sizeof (struct areltdata);
+         current_bfd->arelt_data = bfd_zalloc (current_bfd, size);
+         if (current_bfd->arelt_data == NULL)
+           return FALSE;
+       }
 
-      if (ahdrp == NULL)
+      if (arch_xhdr_big (current_bfd) == NULL)
        {
+         struct xcoff_ar_hdr_big *ahdrp;
          struct stat s;
 
-         ahdrp = &ahdr;
          /* XXX This should actually be a call to stat64 (at least on
             32-bit machines).
             XXX This call will fail if the original object is not found.  */
@@ -2394,68 +2384,57 @@ xcoff_write_archive_contents_big (abfd)
              return FALSE;
            }
 
+         ahdrp = bfd_zalloc (current_bfd, sizeof (*ahdrp));
+         if (ahdrp == NULL)
+           return FALSE;
+
          PRINT20 (ahdrp->size, s.st_size);
          PRINT12 (ahdrp->date, s.st_mtime);
          PRINT12 (ahdrp->uid,  s.st_uid);
          PRINT12 (ahdrp->gid,  s.st_gid);
          PRINT12_OCTAL (ahdrp->mode, s.st_mode);
 
-         if (current_bfd->arelt_data == NULL)
-           {
-             size = sizeof (struct areltdata);
-             current_bfd->arelt_data = bfd_alloc (current_bfd, size);
-             if (current_bfd->arelt_data == NULL)
-               return FALSE;
-           }
-
+         arch_eltdata (current_bfd)->arch_header = (char *) ahdrp;
          arch_eltdata (current_bfd)->parsed_size = s.st_size;
        }
+    }
 
-      PRINT20 (ahdrp->prevoff, prevoff);
-      PRINT4 (ahdrp->namlen, namlen);
-
-      /* If the length of the name is odd, we write out the null byte
-        after the name as well.  */
-      namlen = (namlen + 1) &~ (bfd_size_type) 1;
-
-      remaining = arelt_size (current_bfd);
-      size = (SIZEOF_AR_HDR_BIG
-             + namlen
-             + SXCOFFARFMAG
-             + remaining);
-
-      BFD_ASSERT (nextoff == bfd_tell (abfd));
-
-      /* Check for xcoff shared objects.
-        Their text section needs to be aligned wrt the archive file position.
-        This requires extra padding before the archive header.  */
-      if (! do_shared_object_padding (abfd, current_bfd, & nextoff,
-                                     SIZEOF_AR_HDR_BIG + namlen
-                                     + SXCOFFARFMAG))
+  offsets = NULL;
+  if (count)
+    {
+      offsets = (file_ptr *) bfd_malloc (count * sizeof (file_ptr));
+      if (offsets == NULL)
        return FALSE;
+    }
 
-      offsets[i] = nextoff;
-
-      prevoff = nextoff;
-      nextoff += size + (size & 1);
-
-      PRINT20 (ahdrp->nextoff, nextoff);
+  prevoff = 0;
+  for (archive_iterator_begin (&iterator, abfd), i = 0;
+       archive_iterator_next (&iterator);
+       i++)
+    {
+      bfd_size_type namlen;
+      struct xcoff_ar_hdr_big *ahdrp;
 
-      if ((bfd_bwrite ((PTR) ahdrp, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
-          != SIZEOF_AR_HDR_BIG)
-         || bfd_bwrite ((PTR) name, (bfd_size_type) namlen, abfd) != namlen
-         || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG,
-                         abfd) != SXCOFFARFMAG))
-       return FALSE;
+      ahdrp = arch_xhdr_big (iterator.current.member);
+      PRINT20 (ahdrp->prevoff, prevoff);
+      PRINT4 (ahdrp->namlen, iterator.current.namlen);
+      PRINT20 (ahdrp->nextoff, iterator.next.offset);
 
-      if (bfd_seek (current_bfd, (file_ptr) 0, SEEK_SET) != 0)
+      if (!do_pad (abfd, iterator.current.leading_padding))
        return FALSE;
 
-      if (! do_copy (abfd, current_bfd))
+      BFD_ASSERT (iterator.current.offset == bfd_tell (abfd));
+      namlen = iterator.current.padded_namlen;
+      if (bfd_bwrite (ahdrp, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG
+         || bfd_bwrite (iterator.current.name, namlen, abfd) != namlen
+         || bfd_bwrite (XCOFFARFMAG, SXCOFFARFMAG, abfd) != SXCOFFARFMAG
+         || bfd_seek (iterator.current.member, 0, SEEK_SET) != 0
+         || !do_copy (abfd, iterator.current.member)
+         || !do_pad (abfd, iterator.current.trailing_padding))
        return FALSE;
 
-      if (! do_pad (abfd, size & 1))
-       return FALSE;
+      offsets[i] = iterator.current.offset;
+      prevoff = iterator.current.offset;
     }
 
   if (count)
@@ -2485,6 +2464,7 @@ xcoff_write_archive_contents_big (abfd)
      ??                              pad to even bytes.
    */
 
+  nextoff = iterator.next.offset;
   BFD_ASSERT (nextoff == bfd_tell (abfd));
 
   member_table_size = (SIZEOF_AR_HDR_BIG