[committed] Fix the symbol table in XCOFF archives

Richard Sandiford rdsandiford@googlemail.com
Wed Apr 1 20:04:00 GMT 2009


Another bug found by the libtool testsuite.  If an XCOFF archive
contains a shared object, we try to align the object so that it
can be mapped directly.  But there are several problems:

  (1) We only do this for "big" archives.  We should do it for small
      archives too.

  (2) We work out the padding very late, before writing out the
      shared object's header.  This means that, if the shared object
      isn't the first object, the previous object's header will have
      the wrong nextoff.

  (3) We don't apply the same logic when writing out the symbol table.
      This means that the offsets in the symbol table can be lower
      than they should be.

I don't know how we got away with this for so long.  I only tripped
over it when linking a GNU archive with the native linker.

Tested on powerpc-ibm-aix4.2 (binutils testsuite only) and
powerpc-ibm-aix6.1.  Applied.

Richard


bfd/
	* 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.

Index: bfd/coff-rs6000.c
===================================================================
--- bfd/coff-rs6000.c	2009-04-01 11:32:07.000000000 +0100
+++ bfd/coff-rs6000.c	2009-04-01 11:33:40.000000000 +0100
@@ -180,8 +180,6 @@ #define bfd_pe_print_pdata	NULL
   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[XC
   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, ma
      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, ma
   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, ma
      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, ma
      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, ma
 	    }
 	  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, ma
       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, ma
       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, ma
 		}
 	      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, ma
       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, ma
       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, ma
 		}
 	      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 @@ _bfd_xcoff_write_armap (abfd, elength, m
 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)
+      if (!do_pad (abfd, iterator.current.leading_padding))
 	return FALSE;
 
-      if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
+      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_copy (abfd, sub))
-	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



More information about the Binutils mailing list