13d8817e4Smiod /* BFD back-end for archive files (libraries).
23d8817e4Smiod Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
33d8817e4Smiod 2000, 2001, 2002, 2003, 2004, 2005
43d8817e4Smiod Free Software Foundation, Inc.
53d8817e4Smiod Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault.
63d8817e4Smiod
73d8817e4Smiod This file is part of BFD, the Binary File Descriptor library.
83d8817e4Smiod
93d8817e4Smiod This program is free software; you can redistribute it and/or modify
103d8817e4Smiod it under the terms of the GNU General Public License as published by
113d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
123d8817e4Smiod (at your option) any later version.
133d8817e4Smiod
143d8817e4Smiod This program is distributed in the hope that it will be useful,
153d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
163d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
173d8817e4Smiod GNU General Public License for more details.
183d8817e4Smiod
193d8817e4Smiod You should have received a copy of the GNU General Public License
203d8817e4Smiod along with this program; if not, write to the Free Software
213d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
223d8817e4Smiod
233d8817e4Smiod /*
243d8817e4Smiod @setfilename archive-info
253d8817e4Smiod SECTION
263d8817e4Smiod Archives
273d8817e4Smiod
283d8817e4Smiod DESCRIPTION
293d8817e4Smiod An archive (or library) is just another BFD. It has a symbol
303d8817e4Smiod table, although there's not much a user program will do with it.
313d8817e4Smiod
323d8817e4Smiod The big difference between an archive BFD and an ordinary BFD
333d8817e4Smiod is that the archive doesn't have sections. Instead it has a
343d8817e4Smiod chain of BFDs that are considered its contents. These BFDs can
353d8817e4Smiod be manipulated like any other. The BFDs contained in an
363d8817e4Smiod archive opened for reading will all be opened for reading. You
373d8817e4Smiod may put either input or output BFDs into an archive opened for
383d8817e4Smiod output; they will be handled correctly when the archive is closed.
393d8817e4Smiod
403d8817e4Smiod Use <<bfd_openr_next_archived_file>> to step through
413d8817e4Smiod the contents of an archive opened for input. You don't
423d8817e4Smiod have to read the entire archive if you don't want
433d8817e4Smiod to! Read it until you find what you want.
443d8817e4Smiod
453d8817e4Smiod Archive contents of output BFDs are chained through the
463d8817e4Smiod <<next>> pointer in a BFD. The first one is findable through
473d8817e4Smiod the <<archive_head>> slot of the archive. Set it with
483d8817e4Smiod <<bfd_set_archive_head>> (q.v.). A given BFD may be in only one
493d8817e4Smiod open output archive at a time.
503d8817e4Smiod
513d8817e4Smiod As expected, the BFD archive code is more general than the
523d8817e4Smiod archive code of any given environment. BFD archives may
533d8817e4Smiod contain files of different formats (e.g., a.out and coff) and
543d8817e4Smiod even different architectures. You may even place archives
553d8817e4Smiod recursively into archives!
563d8817e4Smiod
573d8817e4Smiod This can cause unexpected confusion, since some archive
583d8817e4Smiod formats are more expressive than others. For instance, Intel
593d8817e4Smiod COFF archives can preserve long filenames; SunOS a.out archives
603d8817e4Smiod cannot. If you move a file from the first to the second
613d8817e4Smiod format and back again, the filename may be truncated.
623d8817e4Smiod Likewise, different a.out environments have different
633d8817e4Smiod conventions as to how they truncate filenames, whether they
643d8817e4Smiod preserve directory names in filenames, etc. When
653d8817e4Smiod interoperating with native tools, be sure your files are
663d8817e4Smiod homogeneous.
673d8817e4Smiod
683d8817e4Smiod Beware: most of these formats do not react well to the
693d8817e4Smiod presence of spaces in filenames. We do the best we can, but
703d8817e4Smiod can't always handle this case due to restrictions in the format of
713d8817e4Smiod archives. Many Unix utilities are braindead in regards to
723d8817e4Smiod spaces and such in filenames anyway, so this shouldn't be much
733d8817e4Smiod of a restriction.
743d8817e4Smiod
753d8817e4Smiod Archives are supported in BFD in <<archive.c>>.
763d8817e4Smiod
773d8817e4Smiod SUBSECTION
783d8817e4Smiod Archive functions
793d8817e4Smiod */
803d8817e4Smiod
813d8817e4Smiod /* Assumes:
823d8817e4Smiod o - all archive elements start on an even boundary, newline padded;
833d8817e4Smiod o - all arch headers are char *;
843d8817e4Smiod o - all arch headers are the same size (across architectures).
853d8817e4Smiod */
863d8817e4Smiod
873d8817e4Smiod /* Some formats provide a way to cram a long filename into the short
883d8817e4Smiod (16 chars) space provided by a BSD archive. The trick is: make a
893d8817e4Smiod special "file" in the front of the archive, sort of like the SYMDEF
903d8817e4Smiod entry. If the filename is too long to fit, put it in the extended
913d8817e4Smiod name table, and use its index as the filename. To prevent
923d8817e4Smiod confusion prepend the index with a space. This means you can't
933d8817e4Smiod have filenames that start with a space, but then again, many Unix
943d8817e4Smiod utilities can't handle that anyway.
953d8817e4Smiod
963d8817e4Smiod This scheme unfortunately requires that you stand on your head in
973d8817e4Smiod order to write an archive since you need to put a magic file at the
983d8817e4Smiod front, and need to touch every entry to do so. C'est la vie.
993d8817e4Smiod
1003d8817e4Smiod We support two variants of this idea:
1013d8817e4Smiod The SVR4 format (extended name table is named "//"),
1023d8817e4Smiod and an extended pseudo-BSD variant (extended name table is named
1033d8817e4Smiod "ARFILENAMES/"). The origin of the latter format is uncertain.
1043d8817e4Smiod
1053d8817e4Smiod BSD 4.4 uses a third scheme: It writes a long filename
1063d8817e4Smiod directly after the header. This allows 'ar q' to work.
1073d8817e4Smiod We currently can read BSD 4.4 archives, but not write them.
1083d8817e4Smiod */
1093d8817e4Smiod
1103d8817e4Smiod /* Summary of archive member names:
1113d8817e4Smiod
1123d8817e4Smiod Symbol table (must be first):
1133d8817e4Smiod "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib.
1143d8817e4Smiod "/ " - Symbol table, system 5 style.
1153d8817e4Smiod
1163d8817e4Smiod Long name table (must be before regular file members):
1173d8817e4Smiod "// " - Long name table, System 5 R4 style.
1183d8817e4Smiod "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4).
1193d8817e4Smiod
1203d8817e4Smiod Regular file members with short names:
1213d8817e4Smiod "filename.o/ " - Regular file, System 5 style (embedded spaces ok).
1223d8817e4Smiod "filename.o " - Regular file, Berkeley style (no embedded spaces).
1233d8817e4Smiod
1243d8817e4Smiod Regular files with long names (or embedded spaces, for BSD variants):
1253d8817e4Smiod "/18 " - SVR4 style, name at offset 18 in name table.
1263d8817e4Smiod "#1/23 " - Long name (or embedded spaces) 23 characters long,
1273d8817e4Smiod BSD 4.4 style, full name follows header.
1283d8817e4Smiod Implemented for reading, not writing.
1293d8817e4Smiod " 18 " - Long name 18 characters long, extended pseudo-BSD.
1303d8817e4Smiod */
1313d8817e4Smiod
1323d8817e4Smiod #include "bfd.h"
1333d8817e4Smiod #include "sysdep.h"
1343d8817e4Smiod #include "libiberty.h"
1353d8817e4Smiod #include "libbfd.h"
1363d8817e4Smiod #include "aout/ar.h"
1373d8817e4Smiod #include "aout/ranlib.h"
1383d8817e4Smiod #include "safe-ctype.h"
1393d8817e4Smiod #include "hashtab.h"
1403d8817e4Smiod
1413d8817e4Smiod #ifndef errno
1423d8817e4Smiod extern int errno;
1433d8817e4Smiod #endif
1443d8817e4Smiod
1453d8817e4Smiod /* We keep a cache of archive filepointers to archive elements to
1463d8817e4Smiod speed up searching the archive by filepos. We only add an entry to
1473d8817e4Smiod the cache when we actually read one. We also don't sort the cache;
1483d8817e4Smiod it's generally short enough to search linearly.
1493d8817e4Smiod Note that the pointers here point to the front of the ar_hdr, not
1503d8817e4Smiod to the front of the contents! */
1513d8817e4Smiod struct ar_cache {
1523d8817e4Smiod file_ptr ptr;
1533d8817e4Smiod bfd *arbfd;
1543d8817e4Smiod };
1553d8817e4Smiod
1563d8817e4Smiod #define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char)
1573d8817e4Smiod #define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
1583d8817e4Smiod
1593d8817e4Smiod #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
1603d8817e4Smiod #define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata(bfd)->arch_header)
1613d8817e4Smiod
1623d8817e4Smiod void
_bfd_ar_spacepad(char * p,size_t n,const char * fmt,long val)1633d8817e4Smiod _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
1643d8817e4Smiod {
1653d8817e4Smiod static char buf[20];
1663d8817e4Smiod size_t len;
1673d8817e4Smiod snprintf (buf, sizeof (buf), fmt, val);
1683d8817e4Smiod len = strlen (buf);
1693d8817e4Smiod if (len < n)
1703d8817e4Smiod {
1713d8817e4Smiod memcpy (p, buf, len);
1723d8817e4Smiod memset (p + len, ' ', n - len);
1733d8817e4Smiod }
1743d8817e4Smiod else
1753d8817e4Smiod memcpy (p, buf, n);
1763d8817e4Smiod }
1773d8817e4Smiod
17804a47612Sguenther void
_bfd_ar_spacepadll(char * p,size_t n,const char * fmt,long long val)17904a47612Sguenther _bfd_ar_spacepadll (char *p, size_t n, const char *fmt, long long val)
18004a47612Sguenther {
18104a47612Sguenther static char buf[20];
18204a47612Sguenther size_t len;
18304a47612Sguenther snprintf (buf, sizeof (buf), fmt, val);
18404a47612Sguenther len = strlen (buf);
18504a47612Sguenther if (len < n)
18604a47612Sguenther {
18704a47612Sguenther memcpy (p, buf, len);
18804a47612Sguenther memset (p + len, ' ', n - len);
18904a47612Sguenther }
19004a47612Sguenther else
19104a47612Sguenther memcpy (p, buf, n);
19204a47612Sguenther }
19304a47612Sguenther
1943d8817e4Smiod bfd_boolean
_bfd_generic_mkarchive(bfd * abfd)1953d8817e4Smiod _bfd_generic_mkarchive (bfd *abfd)
1963d8817e4Smiod {
1973d8817e4Smiod bfd_size_type amt = sizeof (struct artdata);
1983d8817e4Smiod
1993d8817e4Smiod abfd->tdata.aout_ar_data = bfd_zalloc (abfd, amt);
2003d8817e4Smiod if (bfd_ardata (abfd) == NULL)
2013d8817e4Smiod return FALSE;
2023d8817e4Smiod
2033d8817e4Smiod /* Already cleared by bfd_zalloc above.
2043d8817e4Smiod bfd_ardata (abfd)->cache = NULL;
2053d8817e4Smiod bfd_ardata (abfd)->archive_head = NULL;
2063d8817e4Smiod bfd_ardata (abfd)->symdefs = NULL;
2073d8817e4Smiod bfd_ardata (abfd)->extended_names = NULL;
2083d8817e4Smiod bfd_ardata (abfd)->extended_names_size = 0;
2093d8817e4Smiod bfd_ardata (abfd)->tdata = NULL; */
2103d8817e4Smiod
2113d8817e4Smiod return TRUE;
2123d8817e4Smiod }
2133d8817e4Smiod
2143d8817e4Smiod /*
2153d8817e4Smiod FUNCTION
2163d8817e4Smiod bfd_get_next_mapent
2173d8817e4Smiod
2183d8817e4Smiod SYNOPSIS
2193d8817e4Smiod symindex bfd_get_next_mapent
2203d8817e4Smiod (bfd *abfd, symindex previous, carsym **sym);
2213d8817e4Smiod
2223d8817e4Smiod DESCRIPTION
2233d8817e4Smiod Step through archive @var{abfd}'s symbol table (if it
2243d8817e4Smiod has one). Successively update @var{sym} with the next symbol's
2253d8817e4Smiod information, returning that symbol's (internal) index into the
2263d8817e4Smiod symbol table.
2273d8817e4Smiod
2283d8817e4Smiod Supply <<BFD_NO_MORE_SYMBOLS>> as the @var{previous} entry to get
2293d8817e4Smiod the first one; returns <<BFD_NO_MORE_SYMBOLS>> when you've already
2303d8817e4Smiod got the last one.
2313d8817e4Smiod
2323d8817e4Smiod A <<carsym>> is a canonical archive symbol. The only
2333d8817e4Smiod user-visible element is its name, a null-terminated string.
2343d8817e4Smiod */
2353d8817e4Smiod
2363d8817e4Smiod symindex
bfd_get_next_mapent(bfd * abfd,symindex prev,carsym ** entry)2373d8817e4Smiod bfd_get_next_mapent (bfd *abfd, symindex prev, carsym **entry)
2383d8817e4Smiod {
2393d8817e4Smiod if (!bfd_has_map (abfd))
2403d8817e4Smiod {
2413d8817e4Smiod bfd_set_error (bfd_error_invalid_operation);
2423d8817e4Smiod return BFD_NO_MORE_SYMBOLS;
2433d8817e4Smiod }
2443d8817e4Smiod
2453d8817e4Smiod if (prev == BFD_NO_MORE_SYMBOLS)
2463d8817e4Smiod prev = 0;
2473d8817e4Smiod else
2483d8817e4Smiod ++prev;
2493d8817e4Smiod if (prev >= bfd_ardata (abfd)->symdef_count)
2503d8817e4Smiod return BFD_NO_MORE_SYMBOLS;
2513d8817e4Smiod
2523d8817e4Smiod *entry = (bfd_ardata (abfd)->symdefs + prev);
2533d8817e4Smiod return prev;
2543d8817e4Smiod }
2553d8817e4Smiod
2563d8817e4Smiod /* To be called by backends only. */
2573d8817e4Smiod
2583d8817e4Smiod bfd *
_bfd_create_empty_archive_element_shell(bfd * obfd)2593d8817e4Smiod _bfd_create_empty_archive_element_shell (bfd *obfd)
2603d8817e4Smiod {
2613d8817e4Smiod return _bfd_new_bfd_contained_in (obfd);
2623d8817e4Smiod }
2633d8817e4Smiod
2643d8817e4Smiod /*
2653d8817e4Smiod FUNCTION
2663d8817e4Smiod bfd_set_archive_head
2673d8817e4Smiod
2683d8817e4Smiod SYNOPSIS
2693d8817e4Smiod bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head);
2703d8817e4Smiod
2713d8817e4Smiod DESCRIPTION
2723d8817e4Smiod Set the head of the chain of
2733d8817e4Smiod BFDs contained in the archive @var{output} to @var{new_head}.
2743d8817e4Smiod */
2753d8817e4Smiod
2763d8817e4Smiod bfd_boolean
bfd_set_archive_head(bfd * output_archive,bfd * new_head)2773d8817e4Smiod bfd_set_archive_head (bfd *output_archive, bfd *new_head)
2783d8817e4Smiod {
2793d8817e4Smiod output_archive->archive_head = new_head;
2803d8817e4Smiod return TRUE;
2813d8817e4Smiod }
2823d8817e4Smiod
2833d8817e4Smiod bfd *
_bfd_look_for_bfd_in_cache(bfd * arch_bfd,file_ptr filepos)2843d8817e4Smiod _bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos)
2853d8817e4Smiod {
2863d8817e4Smiod htab_t hash_table = bfd_ardata (arch_bfd)->cache;
2873d8817e4Smiod struct ar_cache m;
2883d8817e4Smiod m.ptr = filepos;
2893d8817e4Smiod
2903d8817e4Smiod if (hash_table)
2913d8817e4Smiod {
2923d8817e4Smiod struct ar_cache *entry = (struct ar_cache *) htab_find (hash_table, &m);
2933d8817e4Smiod if (!entry)
2943d8817e4Smiod return NULL;
2953d8817e4Smiod else
2963d8817e4Smiod return entry->arbfd;
2973d8817e4Smiod }
2983d8817e4Smiod else
2993d8817e4Smiod return NULL;
3003d8817e4Smiod }
3013d8817e4Smiod
3023d8817e4Smiod static hashval_t
hash_file_ptr(const PTR p)3033d8817e4Smiod hash_file_ptr (const PTR p)
3043d8817e4Smiod {
3053d8817e4Smiod return (hashval_t) (((struct ar_cache *) p)->ptr);
3063d8817e4Smiod }
3073d8817e4Smiod
3083d8817e4Smiod /* Returns non-zero if P1 and P2 are equal. */
3093d8817e4Smiod
3103d8817e4Smiod static int
eq_file_ptr(const PTR p1,const PTR p2)3113d8817e4Smiod eq_file_ptr (const PTR p1, const PTR p2)
3123d8817e4Smiod {
3133d8817e4Smiod struct ar_cache *arc1 = (struct ar_cache *) p1;
3143d8817e4Smiod struct ar_cache *arc2 = (struct ar_cache *) p2;
3153d8817e4Smiod return arc1->ptr == arc2->ptr;
3163d8817e4Smiod }
3173d8817e4Smiod
3183d8817e4Smiod /* Kind of stupid to call cons for each one, but we don't do too many. */
3193d8817e4Smiod
3203d8817e4Smiod bfd_boolean
_bfd_add_bfd_to_archive_cache(bfd * arch_bfd,file_ptr filepos,bfd * new_elt)3213d8817e4Smiod _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt)
3223d8817e4Smiod {
3233d8817e4Smiod struct ar_cache *cache;
3243d8817e4Smiod htab_t hash_table = bfd_ardata (arch_bfd)->cache;
3253d8817e4Smiod
3263d8817e4Smiod /* If the hash table hasn't been created, create it. */
3273d8817e4Smiod if (hash_table == NULL)
3283d8817e4Smiod {
3293d8817e4Smiod hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr,
3303d8817e4Smiod NULL, calloc, free);
3313d8817e4Smiod if (hash_table == NULL)
3323d8817e4Smiod return FALSE;
3333d8817e4Smiod bfd_ardata (arch_bfd)->cache = hash_table;
3343d8817e4Smiod }
3353d8817e4Smiod
3363d8817e4Smiod /* Insert new_elt into the hash table by filepos. */
3373d8817e4Smiod cache = bfd_zalloc (arch_bfd, sizeof (struct ar_cache));
3383d8817e4Smiod cache->ptr = filepos;
3393d8817e4Smiod cache->arbfd = new_elt;
3403d8817e4Smiod *htab_find_slot (hash_table, (const void *) cache, INSERT) = cache;
3413d8817e4Smiod
3423d8817e4Smiod return TRUE;
3433d8817e4Smiod }
3443d8817e4Smiod
3453d8817e4Smiod /* The name begins with space. Hence the rest of the name is an index into
3463d8817e4Smiod the string table. */
3473d8817e4Smiod
3483d8817e4Smiod static char *
get_extended_arelt_filename(bfd * arch,const char * name)3493d8817e4Smiod get_extended_arelt_filename (bfd *arch, const char *name)
3503d8817e4Smiod {
3513d8817e4Smiod unsigned long index = 0;
3523d8817e4Smiod
3533d8817e4Smiod /* Should extract string so that I can guarantee not to overflow into
3543d8817e4Smiod the next region, but I'm too lazy. */
3553d8817e4Smiod errno = 0;
3563d8817e4Smiod /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
3573d8817e4Smiod index = strtol (name + 1, NULL, 10);
3583d8817e4Smiod if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
3593d8817e4Smiod {
3603d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
3613d8817e4Smiod return NULL;
3623d8817e4Smiod }
3633d8817e4Smiod
3643d8817e4Smiod return bfd_ardata (arch)->extended_names + index;
3653d8817e4Smiod }
3663d8817e4Smiod
3673d8817e4Smiod /* This functions reads an arch header and returns an areltdata pointer, or
3683d8817e4Smiod NULL on error.
3693d8817e4Smiod
3703d8817e4Smiod Presumes the file pointer is already in the right place (ie pointing
3713d8817e4Smiod to the ar_hdr in the file). Moves the file pointer; on success it
3723d8817e4Smiod should be pointing to the front of the file contents; on failure it
3733d8817e4Smiod could have been moved arbitrarily. */
3743d8817e4Smiod
3753d8817e4Smiod void *
_bfd_generic_read_ar_hdr(bfd * abfd)3763d8817e4Smiod _bfd_generic_read_ar_hdr (bfd *abfd)
3773d8817e4Smiod {
3783d8817e4Smiod return _bfd_generic_read_ar_hdr_mag (abfd, NULL);
3793d8817e4Smiod }
3803d8817e4Smiod
3813d8817e4Smiod /* Alpha ECOFF uses an optional different ARFMAG value, so we have a
3823d8817e4Smiod variant of _bfd_generic_read_ar_hdr which accepts a magic string. */
3833d8817e4Smiod
3843d8817e4Smiod void *
_bfd_generic_read_ar_hdr_mag(bfd * abfd,const char * mag)3853d8817e4Smiod _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
3863d8817e4Smiod {
3873d8817e4Smiod struct ar_hdr hdr;
3883d8817e4Smiod char *hdrp = (char *) &hdr;
3893d8817e4Smiod size_t parsed_size;
3903d8817e4Smiod struct areltdata *ared;
3913d8817e4Smiod char *filename = NULL;
3923d8817e4Smiod bfd_size_type namelen = 0;
3933d8817e4Smiod bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
3943d8817e4Smiod char *allocptr = 0;
3953d8817e4Smiod
3963d8817e4Smiod if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr))
3973d8817e4Smiod {
3983d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
3993d8817e4Smiod bfd_set_error (bfd_error_no_more_archived_files);
4003d8817e4Smiod return NULL;
4013d8817e4Smiod }
4023d8817e4Smiod if (strncmp (hdr.ar_fmag, ARFMAG, 2) != 0
4033d8817e4Smiod && (mag == NULL
4043d8817e4Smiod || strncmp (hdr.ar_fmag, mag, 2) != 0))
4053d8817e4Smiod {
4063d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
4073d8817e4Smiod return NULL;
4083d8817e4Smiod }
4093d8817e4Smiod
4103d8817e4Smiod errno = 0;
4113d8817e4Smiod parsed_size = strtol (hdr.ar_size, NULL, 10);
4123d8817e4Smiod if (errno != 0)
4133d8817e4Smiod {
4143d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
4153d8817e4Smiod return NULL;
4163d8817e4Smiod }
4173d8817e4Smiod
4183d8817e4Smiod /* Extract the filename from the archive - there are two ways to
4193d8817e4Smiod specify an extended name table, either the first char of the
4203d8817e4Smiod name is a space, or it's a slash. */
4213d8817e4Smiod if ((hdr.ar_name[0] == '/'
4223d8817e4Smiod || (hdr.ar_name[0] == ' '
4233d8817e4Smiod && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL))
4243d8817e4Smiod && bfd_ardata (abfd)->extended_names != NULL)
4253d8817e4Smiod {
4263d8817e4Smiod filename = get_extended_arelt_filename (abfd, hdr.ar_name);
4273d8817e4Smiod if (filename == NULL)
4283d8817e4Smiod return NULL;
4293d8817e4Smiod }
4303d8817e4Smiod /* BSD4.4-style long filename.
4313d8817e4Smiod Only implemented for reading, so far! */
4323d8817e4Smiod else if (hdr.ar_name[0] == '#'
4333d8817e4Smiod && hdr.ar_name[1] == '1'
4343d8817e4Smiod && hdr.ar_name[2] == '/'
4353d8817e4Smiod && ISDIGIT (hdr.ar_name[3]))
4363d8817e4Smiod {
4373d8817e4Smiod /* BSD-4.4 extended name */
4383d8817e4Smiod namelen = atoi (&hdr.ar_name[3]);
4393d8817e4Smiod allocsize += namelen + 1;
4403d8817e4Smiod parsed_size -= namelen;
4413d8817e4Smiod
4423d8817e4Smiod allocptr = bfd_zalloc (abfd, allocsize);
4433d8817e4Smiod if (allocptr == NULL)
4443d8817e4Smiod return NULL;
4453d8817e4Smiod filename = (allocptr
4463d8817e4Smiod + sizeof (struct areltdata)
4473d8817e4Smiod + sizeof (struct ar_hdr));
4483d8817e4Smiod if (bfd_bread (filename, namelen, abfd) != namelen)
4493d8817e4Smiod {
4503d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
4513d8817e4Smiod bfd_set_error (bfd_error_no_more_archived_files);
4523d8817e4Smiod return NULL;
4533d8817e4Smiod }
4543d8817e4Smiod filename[namelen] = '\0';
4553d8817e4Smiod }
4563d8817e4Smiod else
4573d8817e4Smiod {
4583d8817e4Smiod /* We judge the end of the name by looking for '/' or ' '.
4593d8817e4Smiod Note: The SYSV format (terminated by '/') allows embedded
4603d8817e4Smiod spaces, so only look for ' ' if we don't find '/'. */
4613d8817e4Smiod
4623d8817e4Smiod char *e;
4633d8817e4Smiod e = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd));
4643d8817e4Smiod if (e == NULL)
4653d8817e4Smiod {
4663d8817e4Smiod e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd));
4673d8817e4Smiod if (e == NULL)
4683d8817e4Smiod e = memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd));
4693d8817e4Smiod }
4703d8817e4Smiod
4713d8817e4Smiod if (e != NULL)
4723d8817e4Smiod namelen = e - hdr.ar_name;
4733d8817e4Smiod else
4743d8817e4Smiod {
4753d8817e4Smiod /* If we didn't find a termination character, then the name
4763d8817e4Smiod must be the entire field. */
4773d8817e4Smiod namelen = ar_maxnamelen (abfd);
4783d8817e4Smiod }
4793d8817e4Smiod
4803d8817e4Smiod allocsize += namelen + 1;
4813d8817e4Smiod }
4823d8817e4Smiod
4833d8817e4Smiod if (!allocptr)
4843d8817e4Smiod {
4853d8817e4Smiod allocptr = bfd_zalloc (abfd, allocsize);
4863d8817e4Smiod if (allocptr == NULL)
4873d8817e4Smiod return NULL;
4883d8817e4Smiod }
4893d8817e4Smiod
4903d8817e4Smiod ared = (struct areltdata *) allocptr;
4913d8817e4Smiod
4923d8817e4Smiod ared->arch_header = allocptr + sizeof (struct areltdata);
4933d8817e4Smiod memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr));
4943d8817e4Smiod ared->parsed_size = parsed_size;
4953d8817e4Smiod
4963d8817e4Smiod if (filename != NULL)
4973d8817e4Smiod ared->filename = filename;
4983d8817e4Smiod else
4993d8817e4Smiod {
5003d8817e4Smiod ared->filename = allocptr + (sizeof (struct areltdata) +
5013d8817e4Smiod sizeof (struct ar_hdr));
5023d8817e4Smiod if (namelen)
5033d8817e4Smiod memcpy (ared->filename, hdr.ar_name, namelen);
5043d8817e4Smiod ared->filename[namelen] = '\0';
5053d8817e4Smiod }
5063d8817e4Smiod
5073d8817e4Smiod return ared;
5083d8817e4Smiod }
5093d8817e4Smiod
5103d8817e4Smiod /* This is an internal function; it's mainly used when indexing
5113d8817e4Smiod through the archive symbol table, but also used to get the next
5123d8817e4Smiod element, since it handles the bookkeeping so nicely for us. */
5133d8817e4Smiod
5143d8817e4Smiod bfd *
_bfd_get_elt_at_filepos(bfd * archive,file_ptr filepos)5153d8817e4Smiod _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
5163d8817e4Smiod {
5173d8817e4Smiod struct areltdata *new_areldata;
5183d8817e4Smiod bfd *n_nfd;
5193d8817e4Smiod
5203d8817e4Smiod if (archive->my_archive)
5213d8817e4Smiod {
5223d8817e4Smiod filepos += archive->origin;
5233d8817e4Smiod archive = archive->my_archive;
5243d8817e4Smiod }
5253d8817e4Smiod
5263d8817e4Smiod n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
5273d8817e4Smiod if (n_nfd)
5283d8817e4Smiod return n_nfd;
5293d8817e4Smiod
5303d8817e4Smiod if (0 > bfd_seek (archive, filepos, SEEK_SET))
5313d8817e4Smiod return NULL;
5323d8817e4Smiod
5333d8817e4Smiod if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL)
5343d8817e4Smiod return NULL;
5353d8817e4Smiod
5363d8817e4Smiod n_nfd = _bfd_create_empty_archive_element_shell (archive);
5373d8817e4Smiod if (n_nfd == NULL)
5383d8817e4Smiod {
5393d8817e4Smiod bfd_release (archive, new_areldata);
5403d8817e4Smiod return NULL;
5413d8817e4Smiod }
5423d8817e4Smiod
5433d8817e4Smiod n_nfd->origin = bfd_tell (archive);
5443d8817e4Smiod n_nfd->arelt_data = new_areldata;
5453d8817e4Smiod n_nfd->filename = new_areldata->filename;
5463d8817e4Smiod
5473d8817e4Smiod if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
5483d8817e4Smiod return n_nfd;
5493d8817e4Smiod
5503d8817e4Smiod /* Huh? */
5513d8817e4Smiod bfd_release (archive, n_nfd);
5523d8817e4Smiod bfd_release (archive, new_areldata);
5533d8817e4Smiod return NULL;
5543d8817e4Smiod }
5553d8817e4Smiod
5563d8817e4Smiod /* Return the BFD which is referenced by the symbol in ABFD indexed by
5573d8817e4Smiod INDEX. INDEX should have been returned by bfd_get_next_mapent. */
5583d8817e4Smiod
5593d8817e4Smiod bfd *
_bfd_generic_get_elt_at_index(bfd * abfd,symindex index)5603d8817e4Smiod _bfd_generic_get_elt_at_index (bfd *abfd, symindex index)
5613d8817e4Smiod {
5623d8817e4Smiod carsym *entry;
5633d8817e4Smiod
5643d8817e4Smiod entry = bfd_ardata (abfd)->symdefs + index;
5653d8817e4Smiod return _bfd_get_elt_at_filepos (abfd, entry->file_offset);
5663d8817e4Smiod }
5673d8817e4Smiod
5683d8817e4Smiod /*
5693d8817e4Smiod FUNCTION
5703d8817e4Smiod bfd_openr_next_archived_file
5713d8817e4Smiod
5723d8817e4Smiod SYNOPSIS
5733d8817e4Smiod bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous);
5743d8817e4Smiod
5753d8817e4Smiod DESCRIPTION
5763d8817e4Smiod Provided a BFD, @var{archive}, containing an archive and NULL, open
5773d8817e4Smiod an input BFD on the first contained element and returns that.
5783d8817e4Smiod Subsequent calls should pass
5793d8817e4Smiod the archive and the previous return value to return a created
5803d8817e4Smiod BFD to the next contained element. NULL is returned when there
5813d8817e4Smiod are no more.
5823d8817e4Smiod */
5833d8817e4Smiod
5843d8817e4Smiod bfd *
bfd_openr_next_archived_file(bfd * archive,bfd * last_file)5853d8817e4Smiod bfd_openr_next_archived_file (bfd *archive, bfd *last_file)
5863d8817e4Smiod {
5873d8817e4Smiod if ((bfd_get_format (archive) != bfd_archive) ||
5883d8817e4Smiod (archive->direction == write_direction))
5893d8817e4Smiod {
5903d8817e4Smiod bfd_set_error (bfd_error_invalid_operation);
5913d8817e4Smiod return NULL;
5923d8817e4Smiod }
5933d8817e4Smiod
5943d8817e4Smiod return BFD_SEND (archive,
5953d8817e4Smiod openr_next_archived_file, (archive, last_file));
5963d8817e4Smiod }
5973d8817e4Smiod
5983d8817e4Smiod bfd *
bfd_generic_openr_next_archived_file(bfd * archive,bfd * last_file)5993d8817e4Smiod bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file)
6003d8817e4Smiod {
6013d8817e4Smiod file_ptr filestart;
6023d8817e4Smiod
6033d8817e4Smiod if (!last_file)
6043d8817e4Smiod filestart = bfd_ardata (archive)->first_file_filepos;
6053d8817e4Smiod else
6063d8817e4Smiod {
6073d8817e4Smiod unsigned int size = arelt_size (last_file);
6083d8817e4Smiod filestart = last_file->origin + size;
6093d8817e4Smiod if (archive->my_archive)
6103d8817e4Smiod filestart -= archive->origin;
6113d8817e4Smiod /* Pad to an even boundary...
6123d8817e4Smiod Note that last_file->origin can be odd in the case of
6133d8817e4Smiod BSD-4.4-style element with a long odd size. */
6143d8817e4Smiod filestart += filestart % 2;
6153d8817e4Smiod }
6163d8817e4Smiod
6173d8817e4Smiod return _bfd_get_elt_at_filepos (archive, filestart);
6183d8817e4Smiod }
6193d8817e4Smiod
6203d8817e4Smiod const bfd_target *
bfd_generic_archive_p(bfd * abfd)6213d8817e4Smiod bfd_generic_archive_p (bfd *abfd)
6223d8817e4Smiod {
6233d8817e4Smiod struct artdata *tdata_hold;
6243d8817e4Smiod char armag[SARMAG + 1];
6253d8817e4Smiod bfd_size_type amt;
6263d8817e4Smiod
6273d8817e4Smiod if (bfd_bread (armag, SARMAG, abfd) != SARMAG)
6283d8817e4Smiod {
6293d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
6303d8817e4Smiod bfd_set_error (bfd_error_wrong_format);
6313d8817e4Smiod return NULL;
6323d8817e4Smiod }
6333d8817e4Smiod
6343d8817e4Smiod if (strncmp (armag, ARMAG, SARMAG) != 0 &&
6353d8817e4Smiod strncmp (armag, ARMAGB, SARMAG) != 0)
6363d8817e4Smiod return 0;
6373d8817e4Smiod
6383d8817e4Smiod tdata_hold = bfd_ardata (abfd);
6393d8817e4Smiod
6403d8817e4Smiod amt = sizeof (struct artdata);
6413d8817e4Smiod bfd_ardata (abfd) = bfd_zalloc (abfd, amt);
6423d8817e4Smiod if (bfd_ardata (abfd) == NULL)
6433d8817e4Smiod {
6443d8817e4Smiod bfd_ardata (abfd) = tdata_hold;
6453d8817e4Smiod return NULL;
6463d8817e4Smiod }
6473d8817e4Smiod
6483d8817e4Smiod bfd_ardata (abfd)->first_file_filepos = SARMAG;
6493d8817e4Smiod /* Cleared by bfd_zalloc above.
6503d8817e4Smiod bfd_ardata (abfd)->cache = NULL;
6513d8817e4Smiod bfd_ardata (abfd)->archive_head = NULL;
6523d8817e4Smiod bfd_ardata (abfd)->symdefs = NULL;
6533d8817e4Smiod bfd_ardata (abfd)->extended_names = NULL;
6543d8817e4Smiod bfd_ardata (abfd)->extended_names_size = 0;
6553d8817e4Smiod bfd_ardata (abfd)->tdata = NULL; */
6563d8817e4Smiod
6573d8817e4Smiod if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))
6583d8817e4Smiod || !BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd)))
6593d8817e4Smiod {
6603d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
6613d8817e4Smiod bfd_set_error (bfd_error_wrong_format);
6623d8817e4Smiod bfd_release (abfd, bfd_ardata (abfd));
6633d8817e4Smiod bfd_ardata (abfd) = tdata_hold;
6643d8817e4Smiod return NULL;
6653d8817e4Smiod }
6663d8817e4Smiod
6673d8817e4Smiod if (bfd_has_map (abfd))
6683d8817e4Smiod {
6693d8817e4Smiod bfd *first;
6703d8817e4Smiod
6713d8817e4Smiod /* This archive has a map, so we may presume that the contents
6723d8817e4Smiod are object files. Make sure that if the first file in the
6733d8817e4Smiod archive can be recognized as an object file, it is for this
6743d8817e4Smiod target. If not, assume that this is the wrong format. If
6753d8817e4Smiod the first file is not an object file, somebody is doing
6763d8817e4Smiod something weird, and we permit it so that ar -t will work.
6773d8817e4Smiod
6783d8817e4Smiod This is done because any normal format will recognize any
6793d8817e4Smiod normal archive, regardless of the format of the object files.
6803d8817e4Smiod We do accept an empty archive. */
6813d8817e4Smiod
6823d8817e4Smiod first = bfd_openr_next_archived_file (abfd, NULL);
6833d8817e4Smiod if (first != NULL)
6843d8817e4Smiod {
6853d8817e4Smiod bfd_boolean fail;
6863d8817e4Smiod
6873d8817e4Smiod first->target_defaulted = FALSE;
6883d8817e4Smiod fail = FALSE;
6893d8817e4Smiod if (bfd_check_format (first, bfd_object)
6903d8817e4Smiod && first->xvec != abfd->xvec)
6913d8817e4Smiod {
6923d8817e4Smiod bfd_set_error (bfd_error_wrong_object_format);
6933d8817e4Smiod bfd_ardata (abfd) = tdata_hold;
6943d8817e4Smiod return NULL;
6953d8817e4Smiod }
6963d8817e4Smiod /* And we ought to close `first' here too. */
6973d8817e4Smiod }
6983d8817e4Smiod }
6993d8817e4Smiod
7003d8817e4Smiod return abfd->xvec;
7013d8817e4Smiod }
7023d8817e4Smiod
7033d8817e4Smiod /* Some constants for a 32 bit BSD archive structure. We do not
7043d8817e4Smiod support 64 bit archives presently; so far as I know, none actually
7053d8817e4Smiod exist. Supporting them would require changing these constants, and
7063d8817e4Smiod changing some H_GET_32 to H_GET_64. */
7073d8817e4Smiod
7083d8817e4Smiod /* The size of an external symdef structure. */
7093d8817e4Smiod #define BSD_SYMDEF_SIZE 8
7103d8817e4Smiod
7113d8817e4Smiod /* The offset from the start of a symdef structure to the file offset. */
7123d8817e4Smiod #define BSD_SYMDEF_OFFSET_SIZE 4
7133d8817e4Smiod
7143d8817e4Smiod /* The size of the symdef count. */
7153d8817e4Smiod #define BSD_SYMDEF_COUNT_SIZE 4
7163d8817e4Smiod
7173d8817e4Smiod /* The size of the string count. */
7183d8817e4Smiod #define BSD_STRING_COUNT_SIZE 4
7193d8817e4Smiod
7203d8817e4Smiod /* Returns FALSE on error, TRUE otherwise. */
7213d8817e4Smiod
7223d8817e4Smiod static bfd_boolean
do_slurp_bsd_armap(bfd * abfd)7233d8817e4Smiod do_slurp_bsd_armap (bfd *abfd)
7243d8817e4Smiod {
7253d8817e4Smiod struct areltdata *mapdata;
7263d8817e4Smiod unsigned int counter;
7273d8817e4Smiod bfd_byte *raw_armap, *rbase;
7283d8817e4Smiod struct artdata *ardata = bfd_ardata (abfd);
7293d8817e4Smiod char *stringbase;
7303d8817e4Smiod bfd_size_type parsed_size, amt;
7313d8817e4Smiod carsym *set;
7323d8817e4Smiod
7333d8817e4Smiod mapdata = _bfd_read_ar_hdr (abfd);
7343d8817e4Smiod if (mapdata == NULL)
7353d8817e4Smiod return FALSE;
7363d8817e4Smiod parsed_size = mapdata->parsed_size;
7373d8817e4Smiod bfd_release (abfd, mapdata); /* Don't need it any more. */
7383d8817e4Smiod
7393d8817e4Smiod raw_armap = bfd_zalloc (abfd, parsed_size);
7403d8817e4Smiod if (raw_armap == NULL)
7413d8817e4Smiod return FALSE;
7423d8817e4Smiod
7433d8817e4Smiod if (bfd_bread (raw_armap, parsed_size, abfd) != parsed_size)
7443d8817e4Smiod {
7453d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
7463d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
7473d8817e4Smiod byebye:
7483d8817e4Smiod bfd_release (abfd, raw_armap);
7493d8817e4Smiod return FALSE;
7503d8817e4Smiod }
7513d8817e4Smiod
7523d8817e4Smiod ardata->symdef_count = H_GET_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE;
7533d8817e4Smiod
7543d8817e4Smiod if (ardata->symdef_count * BSD_SYMDEF_SIZE >
7553d8817e4Smiod parsed_size - BSD_SYMDEF_COUNT_SIZE)
7563d8817e4Smiod {
7573d8817e4Smiod /* Probably we're using the wrong byte ordering. */
7583d8817e4Smiod bfd_set_error (bfd_error_wrong_format);
7593d8817e4Smiod goto byebye;
7603d8817e4Smiod }
7613d8817e4Smiod
7623d8817e4Smiod ardata->cache = 0;
7633d8817e4Smiod rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE;
7643d8817e4Smiod stringbase = ((char *) rbase
7653d8817e4Smiod + ardata->symdef_count * BSD_SYMDEF_SIZE
7663d8817e4Smiod + BSD_STRING_COUNT_SIZE);
7673d8817e4Smiod amt = ardata->symdef_count * sizeof (carsym);
7683d8817e4Smiod ardata->symdefs = bfd_alloc (abfd, amt);
7693d8817e4Smiod if (!ardata->symdefs)
7703d8817e4Smiod return FALSE;
7713d8817e4Smiod
7723d8817e4Smiod for (counter = 0, set = ardata->symdefs;
7733d8817e4Smiod counter < ardata->symdef_count;
7743d8817e4Smiod counter++, set++, rbase += BSD_SYMDEF_SIZE)
7753d8817e4Smiod {
7763d8817e4Smiod set->name = H_GET_32 (abfd, rbase) + stringbase;
7773d8817e4Smiod set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
7783d8817e4Smiod }
7793d8817e4Smiod
7803d8817e4Smiod ardata->first_file_filepos = bfd_tell (abfd);
7813d8817e4Smiod /* Pad to an even boundary if you have to. */
7823d8817e4Smiod ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
7833d8817e4Smiod /* FIXME, we should provide some way to free raw_ardata when
7843d8817e4Smiod we are done using the strings from it. For now, it seems
7853d8817e4Smiod to be allocated on an objalloc anyway... */
7863d8817e4Smiod bfd_has_map (abfd) = TRUE;
7873d8817e4Smiod return TRUE;
7883d8817e4Smiod }
7893d8817e4Smiod
7903d8817e4Smiod /* Returns FALSE on error, TRUE otherwise. */
7913d8817e4Smiod
7923d8817e4Smiod static bfd_boolean
do_slurp_coff_armap(bfd * abfd)7933d8817e4Smiod do_slurp_coff_armap (bfd *abfd)
7943d8817e4Smiod {
7953d8817e4Smiod struct areltdata *mapdata;
7963d8817e4Smiod int *raw_armap, *rawptr;
7973d8817e4Smiod struct artdata *ardata = bfd_ardata (abfd);
7983d8817e4Smiod char *stringbase;
7993d8817e4Smiod bfd_size_type stringsize;
8003d8817e4Smiod unsigned int parsed_size;
8013d8817e4Smiod carsym *carsyms;
8023d8817e4Smiod bfd_size_type nsymz; /* Number of symbols in armap. */
8033d8817e4Smiod bfd_vma (*swap) (const void *);
8043d8817e4Smiod char int_buf[sizeof (long)];
8053d8817e4Smiod bfd_size_type carsym_size, ptrsize;
8063d8817e4Smiod unsigned int i;
8073d8817e4Smiod
8083d8817e4Smiod mapdata = _bfd_read_ar_hdr (abfd);
8093d8817e4Smiod if (mapdata == NULL)
8103d8817e4Smiod return FALSE;
8113d8817e4Smiod parsed_size = mapdata->parsed_size;
8123d8817e4Smiod bfd_release (abfd, mapdata); /* Don't need it any more. */
8133d8817e4Smiod
8143d8817e4Smiod if (bfd_bread (int_buf, 4, abfd) != 4)
8153d8817e4Smiod {
8163d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
8173d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
8183d8817e4Smiod return FALSE;
8193d8817e4Smiod }
8203d8817e4Smiod /* It seems that all numeric information in a coff archive is always
8213d8817e4Smiod in big endian format, nomatter the host or target. */
8223d8817e4Smiod swap = bfd_getb32;
8233d8817e4Smiod nsymz = bfd_getb32 (int_buf);
8243d8817e4Smiod stringsize = parsed_size - (4 * nsymz) - 4;
8253d8817e4Smiod
8263d8817e4Smiod /* ... except that some archive formats are broken, and it may be our
8273d8817e4Smiod fault - the i960 little endian coff sometimes has big and sometimes
8283d8817e4Smiod little, because our tools changed. Here's a horrible hack to clean
8293d8817e4Smiod up the crap. */
8303d8817e4Smiod
8313d8817e4Smiod if (stringsize > 0xfffff
8323d8817e4Smiod && bfd_get_arch (abfd) == bfd_arch_i960
8333d8817e4Smiod && bfd_get_flavour (abfd) == bfd_target_coff_flavour)
8343d8817e4Smiod {
8353d8817e4Smiod /* This looks dangerous, let's do it the other way around. */
8363d8817e4Smiod nsymz = bfd_getl32 (int_buf);
8373d8817e4Smiod stringsize = parsed_size - (4 * nsymz) - 4;
8383d8817e4Smiod swap = bfd_getl32;
8393d8817e4Smiod }
8403d8817e4Smiod
8413d8817e4Smiod /* The coff armap must be read sequentially. So we construct a
8423d8817e4Smiod bsd-style one in core all at once, for simplicity. */
8433d8817e4Smiod
8443d8817e4Smiod if (nsymz > ~ (bfd_size_type) 0 / sizeof (carsym))
8453d8817e4Smiod return FALSE;
8463d8817e4Smiod
8473d8817e4Smiod carsym_size = (nsymz * sizeof (carsym));
8483d8817e4Smiod ptrsize = (4 * nsymz);
8493d8817e4Smiod
8503d8817e4Smiod if (carsym_size + stringsize + 1 <= carsym_size)
8513d8817e4Smiod return FALSE;
8523d8817e4Smiod
8533d8817e4Smiod ardata->symdefs = bfd_zalloc (abfd, carsym_size + stringsize + 1);
8543d8817e4Smiod if (ardata->symdefs == NULL)
8553d8817e4Smiod return FALSE;
8563d8817e4Smiod carsyms = ardata->symdefs;
8573d8817e4Smiod stringbase = ((char *) ardata->symdefs) + carsym_size;
8583d8817e4Smiod
8593d8817e4Smiod /* Allocate and read in the raw offsets. */
8603d8817e4Smiod raw_armap = bfd_alloc (abfd, ptrsize);
8613d8817e4Smiod if (raw_armap == NULL)
8623d8817e4Smiod goto release_symdefs;
8633d8817e4Smiod if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
8643d8817e4Smiod || (bfd_bread (stringbase, stringsize, abfd) != stringsize))
8653d8817e4Smiod {
8663d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
8673d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
8683d8817e4Smiod goto release_raw_armap;
8693d8817e4Smiod }
8703d8817e4Smiod
8713d8817e4Smiod /* OK, build the carsyms. */
8723d8817e4Smiod for (i = 0; i < nsymz; i++)
8733d8817e4Smiod {
8743d8817e4Smiod rawptr = raw_armap + i;
8753d8817e4Smiod carsyms->file_offset = swap ((bfd_byte *) rawptr);
8763d8817e4Smiod carsyms->name = stringbase;
8773d8817e4Smiod stringbase += strlen (stringbase) + 1;
8783d8817e4Smiod carsyms++;
8793d8817e4Smiod }
8803d8817e4Smiod *stringbase = 0;
8813d8817e4Smiod
8823d8817e4Smiod ardata->symdef_count = nsymz;
8833d8817e4Smiod ardata->first_file_filepos = bfd_tell (abfd);
8843d8817e4Smiod /* Pad to an even boundary if you have to. */
8853d8817e4Smiod ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
8863d8817e4Smiod
8873d8817e4Smiod bfd_has_map (abfd) = TRUE;
8883d8817e4Smiod bfd_release (abfd, raw_armap);
8893d8817e4Smiod
8903d8817e4Smiod /* Check for a second archive header (as used by PE). */
8913d8817e4Smiod {
8923d8817e4Smiod struct areltdata *tmp;
8933d8817e4Smiod
8943d8817e4Smiod bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET);
8953d8817e4Smiod tmp = _bfd_read_ar_hdr (abfd);
8963d8817e4Smiod if (tmp != NULL)
8973d8817e4Smiod {
8983d8817e4Smiod if (tmp->arch_header[0] == '/'
8993d8817e4Smiod && tmp->arch_header[1] == ' ')
9003d8817e4Smiod {
9013d8817e4Smiod ardata->first_file_filepos +=
9023d8817e4Smiod (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1;
9033d8817e4Smiod }
9043d8817e4Smiod bfd_release (abfd, tmp);
9053d8817e4Smiod }
9063d8817e4Smiod }
9073d8817e4Smiod
9083d8817e4Smiod return TRUE;
9093d8817e4Smiod
9103d8817e4Smiod release_raw_armap:
9113d8817e4Smiod bfd_release (abfd, raw_armap);
9123d8817e4Smiod release_symdefs:
9133d8817e4Smiod bfd_release (abfd, (ardata)->symdefs);
9143d8817e4Smiod return FALSE;
9153d8817e4Smiod }
9163d8817e4Smiod
9173d8817e4Smiod /* This routine can handle either coff-style or bsd-style armaps.
9183d8817e4Smiod Returns FALSE on error, TRUE otherwise */
9193d8817e4Smiod
9203d8817e4Smiod bfd_boolean
bfd_slurp_armap(bfd * abfd)9213d8817e4Smiod bfd_slurp_armap (bfd *abfd)
9223d8817e4Smiod {
9233d8817e4Smiod char nextname[17];
9243d8817e4Smiod int i = bfd_bread (nextname, 16, abfd);
9253d8817e4Smiod
9263d8817e4Smiod if (i == 0)
9273d8817e4Smiod return TRUE;
9283d8817e4Smiod if (i != 16)
9293d8817e4Smiod return FALSE;
9303d8817e4Smiod
9313d8817e4Smiod if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
9323d8817e4Smiod return FALSE;
9333d8817e4Smiod
9343d8817e4Smiod if (!strncmp (nextname, "__.SYMDEF ", 16)
9353d8817e4Smiod || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */
9363d8817e4Smiod return do_slurp_bsd_armap (abfd);
9373d8817e4Smiod else if (!strncmp (nextname, "/ ", 16))
9383d8817e4Smiod return do_slurp_coff_armap (abfd);
9393d8817e4Smiod else if (!strncmp (nextname, "/SYM64/ ", 16))
9403d8817e4Smiod {
9413d8817e4Smiod /* 64bit ELF (Irix 6) archive. */
9423d8817e4Smiod #ifdef BFD64
9433d8817e4Smiod extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
9443d8817e4Smiod return bfd_elf64_archive_slurp_armap (abfd);
9453d8817e4Smiod #else
9463d8817e4Smiod bfd_set_error (bfd_error_wrong_format);
9473d8817e4Smiod return FALSE;
9483d8817e4Smiod #endif
9493d8817e4Smiod }
9503d8817e4Smiod
9513d8817e4Smiod bfd_has_map (abfd) = FALSE;
9523d8817e4Smiod return TRUE;
9533d8817e4Smiod }
9543d8817e4Smiod
9553d8817e4Smiod /* Returns FALSE on error, TRUE otherwise. */
9563d8817e4Smiod /* Flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
9573d8817e4Smiod header is in a slightly different order and the map name is '/'.
9583d8817e4Smiod This flavour is used by hp300hpux. */
9593d8817e4Smiod
9603d8817e4Smiod #define HPUX_SYMDEF_COUNT_SIZE 2
9613d8817e4Smiod
9623d8817e4Smiod bfd_boolean
bfd_slurp_bsd_armap_f2(bfd * abfd)9633d8817e4Smiod bfd_slurp_bsd_armap_f2 (bfd *abfd)
9643d8817e4Smiod {
9653d8817e4Smiod struct areltdata *mapdata;
9663d8817e4Smiod char nextname[17];
9673d8817e4Smiod unsigned int counter;
9683d8817e4Smiod bfd_byte *raw_armap, *rbase;
9693d8817e4Smiod struct artdata *ardata = bfd_ardata (abfd);
9703d8817e4Smiod char *stringbase;
9713d8817e4Smiod unsigned int stringsize;
9723d8817e4Smiod bfd_size_type amt;
9733d8817e4Smiod carsym *set;
9743d8817e4Smiod int i = bfd_bread (nextname, 16, abfd);
9753d8817e4Smiod
9763d8817e4Smiod if (i == 0)
9773d8817e4Smiod return TRUE;
9783d8817e4Smiod if (i != 16)
9793d8817e4Smiod return FALSE;
9803d8817e4Smiod
9813d8817e4Smiod /* The archive has at least 16 bytes in it. */
9823d8817e4Smiod if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
9833d8817e4Smiod return FALSE;
9843d8817e4Smiod
9853d8817e4Smiod if (!strncmp (nextname, "__.SYMDEF ", 16)
9863d8817e4Smiod || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* Old Linux archives. */
9873d8817e4Smiod return do_slurp_bsd_armap (abfd);
9883d8817e4Smiod
9893d8817e4Smiod if (strncmp (nextname, "/ ", 16))
9903d8817e4Smiod {
9913d8817e4Smiod bfd_has_map (abfd) = FALSE;
9923d8817e4Smiod return TRUE;
9933d8817e4Smiod }
9943d8817e4Smiod
9953d8817e4Smiod mapdata = _bfd_read_ar_hdr (abfd);
9963d8817e4Smiod if (mapdata == NULL)
9973d8817e4Smiod return FALSE;
9983d8817e4Smiod
9993d8817e4Smiod amt = mapdata->parsed_size;
10003d8817e4Smiod raw_armap = bfd_zalloc (abfd, amt);
10013d8817e4Smiod if (raw_armap == NULL)
10023d8817e4Smiod {
10033d8817e4Smiod byebye:
10043d8817e4Smiod bfd_release (abfd, mapdata);
10053d8817e4Smiod return FALSE;
10063d8817e4Smiod }
10073d8817e4Smiod
10083d8817e4Smiod if (bfd_bread (raw_armap, amt, abfd) != amt)
10093d8817e4Smiod {
10103d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
10113d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
10123d8817e4Smiod byebyebye:
10133d8817e4Smiod bfd_release (abfd, raw_armap);
10143d8817e4Smiod goto byebye;
10153d8817e4Smiod }
10163d8817e4Smiod
10173d8817e4Smiod ardata->symdef_count = H_GET_16 (abfd, raw_armap);
10183d8817e4Smiod
10193d8817e4Smiod if (ardata->symdef_count * BSD_SYMDEF_SIZE
10203d8817e4Smiod > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE)
10213d8817e4Smiod {
10223d8817e4Smiod /* Probably we're using the wrong byte ordering. */
10233d8817e4Smiod bfd_set_error (bfd_error_wrong_format);
10243d8817e4Smiod goto byebyebye;
10253d8817e4Smiod }
10263d8817e4Smiod
10273d8817e4Smiod ardata->cache = 0;
10283d8817e4Smiod
10293d8817e4Smiod stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE);
10303d8817e4Smiod /* Skip sym count and string sz. */
10313d8817e4Smiod stringbase = ((char *) raw_armap
10323d8817e4Smiod + HPUX_SYMDEF_COUNT_SIZE
10333d8817e4Smiod + BSD_STRING_COUNT_SIZE);
10343d8817e4Smiod rbase = (bfd_byte *) stringbase + stringsize;
10353d8817e4Smiod amt = ardata->symdef_count * BSD_SYMDEF_SIZE;
10363d8817e4Smiod ardata->symdefs = bfd_alloc (abfd, amt);
10373d8817e4Smiod if (!ardata->symdefs)
10383d8817e4Smiod return FALSE;
10393d8817e4Smiod
10403d8817e4Smiod for (counter = 0, set = ardata->symdefs;
10413d8817e4Smiod counter < ardata->symdef_count;
10423d8817e4Smiod counter++, set++, rbase += BSD_SYMDEF_SIZE)
10433d8817e4Smiod {
10443d8817e4Smiod set->name = H_GET_32 (abfd, rbase) + stringbase;
10453d8817e4Smiod set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
10463d8817e4Smiod }
10473d8817e4Smiod
10483d8817e4Smiod ardata->first_file_filepos = bfd_tell (abfd);
10493d8817e4Smiod /* Pad to an even boundary if you have to. */
10503d8817e4Smiod ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
10513d8817e4Smiod /* FIXME, we should provide some way to free raw_ardata when
10523d8817e4Smiod we are done using the strings from it. For now, it seems
10533d8817e4Smiod to be allocated on an objalloc anyway... */
10543d8817e4Smiod bfd_has_map (abfd) = TRUE;
10553d8817e4Smiod return TRUE;
10563d8817e4Smiod }
10573d8817e4Smiod
10583d8817e4Smiod /** Extended name table.
10593d8817e4Smiod
10603d8817e4Smiod Normally archives support only 14-character filenames.
10613d8817e4Smiod
10623d8817e4Smiod Intel has extended the format: longer names are stored in a special
10633d8817e4Smiod element (the first in the archive, or second if there is an armap);
10643d8817e4Smiod the name in the ar_hdr is replaced by <space><index into filename
10653d8817e4Smiod element>. Index is the P.R. of an int (decimal). Data General have
10663d8817e4Smiod extended the format by using the prefix // for the special element. */
10673d8817e4Smiod
10683d8817e4Smiod /* Returns FALSE on error, TRUE otherwise. */
10693d8817e4Smiod
10703d8817e4Smiod bfd_boolean
_bfd_slurp_extended_name_table(bfd * abfd)10713d8817e4Smiod _bfd_slurp_extended_name_table (bfd *abfd)
10723d8817e4Smiod {
10733d8817e4Smiod char nextname[17];
10743d8817e4Smiod struct areltdata *namedata;
10753d8817e4Smiod bfd_size_type amt;
10763d8817e4Smiod
10773d8817e4Smiod /* FIXME: Formatting sucks here, and in case of failure of BFD_READ,
10783d8817e4Smiod we probably don't want to return TRUE. */
10793d8817e4Smiod bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET);
10803d8817e4Smiod if (bfd_bread (nextname, 16, abfd) == 16)
10813d8817e4Smiod {
10823d8817e4Smiod if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
10833d8817e4Smiod return FALSE;
10843d8817e4Smiod
10853d8817e4Smiod if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
10863d8817e4Smiod strncmp (nextname, "// ", 16) != 0)
10873d8817e4Smiod {
10883d8817e4Smiod bfd_ardata (abfd)->extended_names = NULL;
10893d8817e4Smiod bfd_ardata (abfd)->extended_names_size = 0;
10903d8817e4Smiod return TRUE;
10913d8817e4Smiod }
10923d8817e4Smiod
10933d8817e4Smiod namedata = _bfd_read_ar_hdr (abfd);
10943d8817e4Smiod if (namedata == NULL)
10953d8817e4Smiod return FALSE;
10963d8817e4Smiod
10973d8817e4Smiod amt = namedata->parsed_size;
10983d8817e4Smiod if (amt + 1 == 0)
10993d8817e4Smiod goto byebye;
11003d8817e4Smiod
11013d8817e4Smiod bfd_ardata (abfd)->extended_names_size = amt;
11023d8817e4Smiod bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt + 1);
11033d8817e4Smiod if (bfd_ardata (abfd)->extended_names == NULL)
11043d8817e4Smiod {
11053d8817e4Smiod byebye:
11063d8817e4Smiod bfd_release (abfd, namedata);
11073d8817e4Smiod return FALSE;
11083d8817e4Smiod }
11093d8817e4Smiod
11103d8817e4Smiod if (bfd_bread (bfd_ardata (abfd)->extended_names, amt, abfd) != amt)
11113d8817e4Smiod {
11123d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
11133d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
11143d8817e4Smiod bfd_release (abfd, (bfd_ardata (abfd)->extended_names));
11153d8817e4Smiod bfd_ardata (abfd)->extended_names = NULL;
11163d8817e4Smiod goto byebye;
11173d8817e4Smiod }
11183d8817e4Smiod
11193d8817e4Smiod /* Since the archive is supposed to be printable if it contains
11203d8817e4Smiod text, the entries in the list are newline-padded, not null
11213d8817e4Smiod padded. In SVR4-style archives, the names also have a
11223d8817e4Smiod trailing '/'. DOS/NT created archive often have \ in them
11233d8817e4Smiod We'll fix all problems here.. */
11243d8817e4Smiod {
11253d8817e4Smiod char *ext_names = bfd_ardata (abfd)->extended_names;
11263d8817e4Smiod char *temp = ext_names;
11273d8817e4Smiod char *limit = temp + namedata->parsed_size;
11283d8817e4Smiod for (; temp < limit; ++temp)
11293d8817e4Smiod {
11303d8817e4Smiod if (*temp == '\012')
11313d8817e4Smiod temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0';
11323d8817e4Smiod if (*temp == '\\')
11333d8817e4Smiod *temp = '/';
11343d8817e4Smiod }
11353d8817e4Smiod *limit = '\0';
11363d8817e4Smiod }
11373d8817e4Smiod
11383d8817e4Smiod /* Pad to an even boundary if you have to. */
11393d8817e4Smiod bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd);
11403d8817e4Smiod bfd_ardata (abfd)->first_file_filepos +=
11413d8817e4Smiod (bfd_ardata (abfd)->first_file_filepos) % 2;
11423d8817e4Smiod
11433d8817e4Smiod /* FIXME, we can't release namedata here because it was allocated
11443d8817e4Smiod below extended_names on the objalloc... */
11453d8817e4Smiod }
11463d8817e4Smiod return TRUE;
11473d8817e4Smiod }
11483d8817e4Smiod
11493d8817e4Smiod #ifdef VMS
11503d8817e4Smiod
11513d8817e4Smiod /* Return a copy of the stuff in the filename between any :]> and a
11523d8817e4Smiod semicolon. */
11533d8817e4Smiod
11543d8817e4Smiod static const char *
normalize(bfd * abfd,const char * file)11553d8817e4Smiod normalize (bfd *abfd, const char *file)
11563d8817e4Smiod {
11573d8817e4Smiod const char *first;
11583d8817e4Smiod const char *last;
11593d8817e4Smiod char *copy;
11603d8817e4Smiod
11613d8817e4Smiod first = file + strlen (file) - 1;
11623d8817e4Smiod last = first + 1;
11633d8817e4Smiod
11643d8817e4Smiod while (first != file)
11653d8817e4Smiod {
11663d8817e4Smiod if (*first == ';')
11673d8817e4Smiod last = first;
11683d8817e4Smiod if (*first == ':' || *first == ']' || *first == '>')
11693d8817e4Smiod {
11703d8817e4Smiod first++;
11713d8817e4Smiod break;
11723d8817e4Smiod }
11733d8817e4Smiod first--;
11743d8817e4Smiod }
11753d8817e4Smiod
11763d8817e4Smiod copy = bfd_alloc (abfd, last - first + 1);
11773d8817e4Smiod if (copy == NULL)
11783d8817e4Smiod return NULL;
11793d8817e4Smiod
11803d8817e4Smiod memcpy (copy, first, last - first);
11813d8817e4Smiod copy[last - first] = 0;
11823d8817e4Smiod
11833d8817e4Smiod return copy;
11843d8817e4Smiod }
11853d8817e4Smiod
11863d8817e4Smiod #else
11873d8817e4Smiod static const char *
normalize(bfd * abfd ATTRIBUTE_UNUSED,const char * file)11883d8817e4Smiod normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file)
11893d8817e4Smiod {
11903d8817e4Smiod const char *filename = strrchr (file, '/');
11913d8817e4Smiod
11923d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
11933d8817e4Smiod {
11943d8817e4Smiod /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
11953d8817e4Smiod char *bslash = strrchr (file, '\\');
11963d8817e4Smiod if (filename == NULL || (bslash != NULL && bslash > filename))
11973d8817e4Smiod filename = bslash;
11983d8817e4Smiod if (filename == NULL && file[0] != '\0' && file[1] == ':')
11993d8817e4Smiod filename = file + 1;
12003d8817e4Smiod }
12013d8817e4Smiod #endif
12023d8817e4Smiod if (filename != NULL)
12033d8817e4Smiod filename++;
12043d8817e4Smiod else
12053d8817e4Smiod filename = file;
12063d8817e4Smiod return filename;
12073d8817e4Smiod }
12083d8817e4Smiod #endif
12093d8817e4Smiod
12103d8817e4Smiod /* Build a BFD style extended name table. */
12113d8817e4Smiod
12123d8817e4Smiod bfd_boolean
_bfd_archive_bsd_construct_extended_name_table(bfd * abfd,char ** tabloc,bfd_size_type * tablen,const char ** name)12133d8817e4Smiod _bfd_archive_bsd_construct_extended_name_table (bfd *abfd,
12143d8817e4Smiod char **tabloc,
12153d8817e4Smiod bfd_size_type *tablen,
12163d8817e4Smiod const char **name)
12173d8817e4Smiod {
12183d8817e4Smiod *name = "ARFILENAMES/";
12193d8817e4Smiod return _bfd_construct_extended_name_table (abfd, FALSE, tabloc, tablen);
12203d8817e4Smiod }
12213d8817e4Smiod
12223d8817e4Smiod /* Build an SVR4 style extended name table. */
12233d8817e4Smiod
12243d8817e4Smiod bfd_boolean
_bfd_archive_coff_construct_extended_name_table(bfd * abfd,char ** tabloc,bfd_size_type * tablen,const char ** name)12253d8817e4Smiod _bfd_archive_coff_construct_extended_name_table (bfd *abfd,
12263d8817e4Smiod char **tabloc,
12273d8817e4Smiod bfd_size_type *tablen,
12283d8817e4Smiod const char **name)
12293d8817e4Smiod {
12303d8817e4Smiod *name = "//";
12313d8817e4Smiod return _bfd_construct_extended_name_table (abfd, TRUE, tabloc, tablen);
12323d8817e4Smiod }
12333d8817e4Smiod
12343d8817e4Smiod /* Follows archive_head and produces an extended name table if
12353d8817e4Smiod necessary. Returns (in tabloc) a pointer to an extended name
12363d8817e4Smiod table, and in tablen the length of the table. If it makes an entry
12373d8817e4Smiod it clobbers the filename so that the element may be written without
12383d8817e4Smiod further massage. Returns TRUE if it ran successfully, FALSE if
12393d8817e4Smiod something went wrong. A successful return may still involve a
12403d8817e4Smiod zero-length tablen! */
12413d8817e4Smiod
12423d8817e4Smiod bfd_boolean
_bfd_construct_extended_name_table(bfd * abfd,bfd_boolean trailing_slash,char ** tabloc,bfd_size_type * tablen)12433d8817e4Smiod _bfd_construct_extended_name_table (bfd *abfd,
12443d8817e4Smiod bfd_boolean trailing_slash,
12453d8817e4Smiod char **tabloc,
12463d8817e4Smiod bfd_size_type *tablen)
12473d8817e4Smiod {
12483d8817e4Smiod unsigned int maxname = abfd->xvec->ar_max_namelen;
12493d8817e4Smiod bfd_size_type total_namelen = 0;
12503d8817e4Smiod bfd *current;
12513d8817e4Smiod char *strptr;
12523d8817e4Smiod
12533d8817e4Smiod *tablen = 0;
12543d8817e4Smiod
12553d8817e4Smiod /* Figure out how long the table should be. */
12563d8817e4Smiod for (current = abfd->archive_head; current != NULL; current = current->next)
12573d8817e4Smiod {
12583d8817e4Smiod const char *normal;
12593d8817e4Smiod unsigned int thislen;
12603d8817e4Smiod
12613d8817e4Smiod normal = normalize (current, current->filename);
12623d8817e4Smiod if (normal == NULL)
12633d8817e4Smiod return FALSE;
12643d8817e4Smiod
12653d8817e4Smiod thislen = strlen (normal);
12663d8817e4Smiod
12673d8817e4Smiod if (thislen > maxname
12683d8817e4Smiod && (bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0)
12693d8817e4Smiod thislen = maxname;
12703d8817e4Smiod
12713d8817e4Smiod if (thislen > maxname)
12723d8817e4Smiod {
12733d8817e4Smiod /* Add one to leave room for \n. */
12743d8817e4Smiod total_namelen += thislen + 1;
12753d8817e4Smiod if (trailing_slash)
12763d8817e4Smiod {
12773d8817e4Smiod /* Leave room for trailing slash. */
12783d8817e4Smiod ++total_namelen;
12793d8817e4Smiod }
12803d8817e4Smiod }
12813d8817e4Smiod else
12823d8817e4Smiod {
12833d8817e4Smiod struct ar_hdr *hdr = arch_hdr (current);
12843d8817e4Smiod if (strncmp (normal, hdr->ar_name, thislen) != 0
12853d8817e4Smiod || (thislen < sizeof hdr->ar_name
12863d8817e4Smiod && hdr->ar_name[thislen] != ar_padchar (current)))
12873d8817e4Smiod {
12883d8817e4Smiod /* Must have been using extended format even though it
12893d8817e4Smiod didn't need to. Fix it to use normal format. */
12903d8817e4Smiod memcpy (hdr->ar_name, normal, thislen);
12913d8817e4Smiod if (thislen < maxname
12923d8817e4Smiod || (thislen == maxname && thislen < sizeof hdr->ar_name))
12933d8817e4Smiod hdr->ar_name[thislen] = ar_padchar (current);
12943d8817e4Smiod }
12953d8817e4Smiod }
12963d8817e4Smiod }
12973d8817e4Smiod
12983d8817e4Smiod if (total_namelen == 0)
12993d8817e4Smiod return TRUE;
13003d8817e4Smiod
13013d8817e4Smiod *tabloc = bfd_zalloc (abfd, total_namelen);
13023d8817e4Smiod if (*tabloc == NULL)
13033d8817e4Smiod return FALSE;
13043d8817e4Smiod
13053d8817e4Smiod *tablen = total_namelen;
13063d8817e4Smiod strptr = *tabloc;
13073d8817e4Smiod
13083d8817e4Smiod for (current = abfd->archive_head; current != NULL; current =
13093d8817e4Smiod current->next)
13103d8817e4Smiod {
13113d8817e4Smiod const char *normal;
13123d8817e4Smiod unsigned int thislen;
13133d8817e4Smiod
13143d8817e4Smiod normal = normalize (current, current->filename);
13153d8817e4Smiod if (normal == NULL)
13163d8817e4Smiod return FALSE;
13173d8817e4Smiod
13183d8817e4Smiod thislen = strlen (normal);
13193d8817e4Smiod if (thislen > maxname)
13203d8817e4Smiod {
13213d8817e4Smiod /* Works for now; may need to be re-engineered if we
13223d8817e4Smiod encounter an oddball archive format and want to
13233d8817e4Smiod generalise this hack. */
13243d8817e4Smiod struct ar_hdr *hdr = arch_hdr (current);
13253d8817e4Smiod strcpy (strptr, normal);
13263d8817e4Smiod if (! trailing_slash)
13273d8817e4Smiod strptr[thislen] = '\012';
13283d8817e4Smiod else
13293d8817e4Smiod {
13303d8817e4Smiod strptr[thislen] = '/';
13313d8817e4Smiod strptr[thislen + 1] = '\012';
13323d8817e4Smiod }
13333d8817e4Smiod hdr->ar_name[0] = ar_padchar (current);
13343d8817e4Smiod _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld",
13353d8817e4Smiod strptr - *tabloc);
13363d8817e4Smiod strptr += thislen + 1;
13373d8817e4Smiod if (trailing_slash)
13383d8817e4Smiod ++strptr;
13393d8817e4Smiod }
13403d8817e4Smiod }
13413d8817e4Smiod
13423d8817e4Smiod return TRUE;
13433d8817e4Smiod }
13443d8817e4Smiod
13453d8817e4Smiod /* A couple of functions for creating ar_hdrs. */
13463d8817e4Smiod
13473d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
13483d8817e4Smiod /* Function to encode large UID/GID values according to HP. */
13493d8817e4Smiod
13503d8817e4Smiod static void
hpux_uid_gid_encode(char str[6],long int id)13513d8817e4Smiod hpux_uid_gid_encode (char str[6], long int id)
13523d8817e4Smiod {
13533d8817e4Smiod int cnt;
13543d8817e4Smiod
13553d8817e4Smiod str[5] = '@' + (id & 3);
13563d8817e4Smiod id >>= 2;
13573d8817e4Smiod
13583d8817e4Smiod for (cnt = 4; cnt >= 0; ++cnt, id >>= 6)
13593d8817e4Smiod str[cnt] = ' ' + (id & 0x3f);
13603d8817e4Smiod }
13613d8817e4Smiod #endif /* HPUX_LARGE_AR_IDS */
13623d8817e4Smiod
13633d8817e4Smiod #ifndef HAVE_GETUID
13643d8817e4Smiod #define getuid() 0
13653d8817e4Smiod #endif
13663d8817e4Smiod
13673d8817e4Smiod #ifndef HAVE_GETGID
13683d8817e4Smiod #define getgid() 0
13693d8817e4Smiod #endif
13703d8817e4Smiod
13713d8817e4Smiod /* Takes a filename, returns an arelt_data for it, or NULL if it can't
13723d8817e4Smiod make one. The filename must refer to a filename in the filesystem.
13733d8817e4Smiod The filename field of the ar_hdr will NOT be initialized. If member
13743d8817e4Smiod is set, and it's an in-memory bfd, we fake it. */
13753d8817e4Smiod
13763d8817e4Smiod static struct areltdata *
bfd_ar_hdr_from_filesystem(bfd * abfd,const char * filename,bfd * member)13773d8817e4Smiod bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member)
13783d8817e4Smiod {
13793d8817e4Smiod struct stat status;
13803d8817e4Smiod struct areltdata *ared;
13813d8817e4Smiod struct ar_hdr *hdr;
13823d8817e4Smiod bfd_size_type amt;
13833d8817e4Smiod
13843d8817e4Smiod if (member && (member->flags & BFD_IN_MEMORY) != 0)
13853d8817e4Smiod {
13863d8817e4Smiod /* Assume we just "made" the member, and fake it. */
13873d8817e4Smiod struct bfd_in_memory *bim = member->iostream;
13883d8817e4Smiod time (&status.st_mtime);
13893d8817e4Smiod status.st_uid = getuid ();
13903d8817e4Smiod status.st_gid = getgid ();
13913d8817e4Smiod status.st_mode = 0644;
13923d8817e4Smiod status.st_size = bim->size;
13933d8817e4Smiod }
13943d8817e4Smiod else if (stat (filename, &status) != 0)
13953d8817e4Smiod {
13963d8817e4Smiod bfd_set_error (bfd_error_system_call);
13973d8817e4Smiod return NULL;
13983d8817e4Smiod }
13993d8817e4Smiod
1400*314e8fdfSguenther if ((abfd->flags & BFD_DETERMINISTIC) != 0)
1401*314e8fdfSguenther {
1402*314e8fdfSguenther status.st_mtime = 0;
1403*314e8fdfSguenther status.st_uid = 0;
1404*314e8fdfSguenther status.st_gid = 0;
1405*314e8fdfSguenther status.st_mode = 0644;
1406*314e8fdfSguenther }
1407*314e8fdfSguenther
14083d8817e4Smiod amt = sizeof (struct ar_hdr) + sizeof (struct areltdata);
14093d8817e4Smiod ared = bfd_zalloc (abfd, amt);
14103d8817e4Smiod if (ared == NULL)
14113d8817e4Smiod return NULL;
14123d8817e4Smiod hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
14133d8817e4Smiod
14143d8817e4Smiod /* ar headers are space padded, not null padded! */
14153d8817e4Smiod memset (hdr, ' ', sizeof (struct ar_hdr));
14163d8817e4Smiod
141704a47612Sguenther _bfd_ar_spacepadll (hdr->ar_date, sizeof (hdr->ar_date), "%-12lld",
141804a47612Sguenther status.st_mtime);
14193d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14203d8817e4Smiod /* HP has a very "special" way to handle UID/GID's with numeric values
14213d8817e4Smiod > 99999. */
14223d8817e4Smiod if (status.st_uid > 99999)
14233d8817e4Smiod hpux_uid_gid_encode (hdr->ar_uid, (long) status.st_uid);
14243d8817e4Smiod else
14253d8817e4Smiod #endif
14263d8817e4Smiod _bfd_ar_spacepad (hdr->ar_uid, sizeof (hdr->ar_uid), "%ld",
14273d8817e4Smiod status.st_uid);
14283d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14293d8817e4Smiod /* HP has a very "special" way to handle UID/GID's with numeric values
14303d8817e4Smiod > 99999. */
14313d8817e4Smiod if (status.st_gid > 99999)
14323d8817e4Smiod hpux_uid_gid_encode (hdr->ar_gid, (long) status.st_gid);
14333d8817e4Smiod else
14343d8817e4Smiod #endif
14353d8817e4Smiod _bfd_ar_spacepad (hdr->ar_gid, sizeof (hdr->ar_gid), "%ld",
14363d8817e4Smiod status.st_gid);
14373d8817e4Smiod _bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo",
14383d8817e4Smiod status.st_mode);
143904a47612Sguenther _bfd_ar_spacepadll (hdr->ar_size, sizeof (hdr->ar_size), "%-10lld",
14403d8817e4Smiod status.st_size);
14413d8817e4Smiod memcpy (hdr->ar_fmag, ARFMAG, 2);
14423d8817e4Smiod ared->parsed_size = status.st_size;
14433d8817e4Smiod ared->arch_header = (char *) hdr;
14443d8817e4Smiod
14453d8817e4Smiod return ared;
14463d8817e4Smiod }
14473d8817e4Smiod
14483d8817e4Smiod /* This is magic required by the "ar" program. Since it's
14493d8817e4Smiod undocumented, it's undocumented. You may think that it would take
14503d8817e4Smiod a strong stomach to write this, and it does, but it takes even a
14513d8817e4Smiod stronger stomach to try to code around such a thing! */
14523d8817e4Smiod
14533d8817e4Smiod struct ar_hdr *bfd_special_undocumented_glue (bfd *, const char *);
14543d8817e4Smiod
14553d8817e4Smiod struct ar_hdr *
bfd_special_undocumented_glue(bfd * abfd,const char * filename)14563d8817e4Smiod bfd_special_undocumented_glue (bfd *abfd, const char *filename)
14573d8817e4Smiod {
14583d8817e4Smiod struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0);
14593d8817e4Smiod if (ar_elt == NULL)
14603d8817e4Smiod return NULL;
14613d8817e4Smiod return (struct ar_hdr *) ar_elt->arch_header;
14623d8817e4Smiod }
14633d8817e4Smiod
14643d8817e4Smiod /* Analogous to stat call. */
14653d8817e4Smiod
14663d8817e4Smiod int
bfd_generic_stat_arch_elt(bfd * abfd,struct stat * buf)14673d8817e4Smiod bfd_generic_stat_arch_elt (bfd *abfd, struct stat *buf)
14683d8817e4Smiod {
14693d8817e4Smiod struct ar_hdr *hdr;
14703d8817e4Smiod char *aloser;
14713d8817e4Smiod
14723d8817e4Smiod if (abfd->arelt_data == NULL)
14733d8817e4Smiod {
14743d8817e4Smiod bfd_set_error (bfd_error_invalid_operation);
14753d8817e4Smiod return -1;
14763d8817e4Smiod }
14773d8817e4Smiod
14783d8817e4Smiod hdr = arch_hdr (abfd);
14793d8817e4Smiod
14803d8817e4Smiod #define foo(arelt, stelt, size) \
14813d8817e4Smiod buf->stelt = strtol (hdr->arelt, &aloser, size); \
14823d8817e4Smiod if (aloser == hdr->arelt) \
14833d8817e4Smiod return -1;
14843d8817e4Smiod
1485d04417c8Smiod #define fooll(arelt, stelt, size) \
1486d04417c8Smiod buf->stelt = strtoll (hdr->arelt, &aloser, size); \
1487d04417c8Smiod if (aloser == hdr->arelt) \
1488d04417c8Smiod return -1;
1489d04417c8Smiod
14903d8817e4Smiod /* Some platforms support special notations for large IDs. */
14913d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14923d8817e4Smiod # define foo2(arelt, stelt, size) \
14933d8817e4Smiod if (hdr->arelt[5] == ' ') \
14943d8817e4Smiod { \
14953d8817e4Smiod foo (arelt, stelt, size); \
14963d8817e4Smiod } \
14973d8817e4Smiod else \
14983d8817e4Smiod { \
14993d8817e4Smiod int cnt; \
15003d8817e4Smiod for (buf->stelt = cnt = 0; cnt < 5; ++cnt) \
15013d8817e4Smiod { \
15023d8817e4Smiod if (hdr->arelt[cnt] < ' ' || hdr->arelt[cnt] > ' ' + 0x3f) \
15033d8817e4Smiod return -1; \
15043d8817e4Smiod buf->stelt <<= 6; \
15053d8817e4Smiod buf->stelt += hdr->arelt[cnt] - ' '; \
15063d8817e4Smiod } \
15073d8817e4Smiod if (hdr->arelt[5] < '@' || hdr->arelt[5] > '@' + 3) \
15083d8817e4Smiod return -1; \
15093d8817e4Smiod buf->stelt <<= 2; \
15103d8817e4Smiod buf->stelt += hdr->arelt[5] - '@'; \
15113d8817e4Smiod }
15123d8817e4Smiod #else
15133d8817e4Smiod # define foo2(arelt, stelt, size) foo (arelt, stelt, size)
15143d8817e4Smiod #endif
15153d8817e4Smiod
1516d04417c8Smiod fooll (ar_date, st_mtime, 10);
15173d8817e4Smiod foo2 (ar_uid, st_uid, 10);
15183d8817e4Smiod foo2 (ar_gid, st_gid, 10);
15193d8817e4Smiod foo (ar_mode, st_mode, 8);
15203d8817e4Smiod
15213d8817e4Smiod buf->st_size = arch_eltdata (abfd)->parsed_size;
15223d8817e4Smiod
15233d8817e4Smiod return 0;
15243d8817e4Smiod }
15253d8817e4Smiod
15263d8817e4Smiod void
bfd_dont_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)15273d8817e4Smiod bfd_dont_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
15283d8817e4Smiod {
15293d8817e4Smiod /* FIXME: This interacts unpleasantly with ar's quick-append option.
15303d8817e4Smiod Fortunately ic960 users will never use that option. Fixing this
15313d8817e4Smiod is very hard; fortunately I know how to do it and will do so once
15323d8817e4Smiod intel's release is out the door. */
15333d8817e4Smiod
15343d8817e4Smiod struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
15353d8817e4Smiod size_t length;
15363d8817e4Smiod const char *filename;
15373d8817e4Smiod size_t maxlen = ar_maxnamelen (abfd);
15383d8817e4Smiod
15393d8817e4Smiod if ((bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0)
15403d8817e4Smiod {
15413d8817e4Smiod bfd_bsd_truncate_arname (abfd, pathname, arhdr);
15423d8817e4Smiod return;
15433d8817e4Smiod }
15443d8817e4Smiod
15453d8817e4Smiod filename = normalize (abfd, pathname);
15463d8817e4Smiod if (filename == NULL)
15473d8817e4Smiod {
15483d8817e4Smiod /* FIXME */
15493d8817e4Smiod abort ();
15503d8817e4Smiod }
15513d8817e4Smiod
15523d8817e4Smiod length = strlen (filename);
15533d8817e4Smiod
15543d8817e4Smiod if (length <= maxlen)
15553d8817e4Smiod memcpy (hdr->ar_name, filename, length);
15563d8817e4Smiod
15573d8817e4Smiod /* Add the padding character if there is room for it. */
15583d8817e4Smiod if (length < maxlen
15593d8817e4Smiod || (length == maxlen && length < sizeof hdr->ar_name))
15603d8817e4Smiod (hdr->ar_name)[length] = ar_padchar (abfd);
15613d8817e4Smiod }
15623d8817e4Smiod
15633d8817e4Smiod void
bfd_bsd_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)15643d8817e4Smiod bfd_bsd_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
15653d8817e4Smiod {
15663d8817e4Smiod struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
15673d8817e4Smiod size_t length;
15683d8817e4Smiod const char *filename = strrchr (pathname, '/');
15693d8817e4Smiod size_t maxlen = ar_maxnamelen (abfd);
15703d8817e4Smiod
15713d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
15723d8817e4Smiod {
15733d8817e4Smiod /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
15743d8817e4Smiod char *bslash = strrchr (pathname, '\\');
15753d8817e4Smiod if (filename == NULL || (bslash != NULL && bslash > filename))
15763d8817e4Smiod filename = bslash;
15773d8817e4Smiod if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
15783d8817e4Smiod filename = pathname + 1;
15793d8817e4Smiod }
15803d8817e4Smiod #endif
15813d8817e4Smiod
15823d8817e4Smiod if (filename == NULL)
15833d8817e4Smiod filename = pathname;
15843d8817e4Smiod else
15853d8817e4Smiod ++filename;
15863d8817e4Smiod
15873d8817e4Smiod length = strlen (filename);
15883d8817e4Smiod
15893d8817e4Smiod if (length <= maxlen)
15903d8817e4Smiod memcpy (hdr->ar_name, filename, length);
15913d8817e4Smiod else
15923d8817e4Smiod {
15933d8817e4Smiod /* pathname: meet procrustes */
15943d8817e4Smiod memcpy (hdr->ar_name, filename, maxlen);
15953d8817e4Smiod length = maxlen;
15963d8817e4Smiod }
15973d8817e4Smiod
15983d8817e4Smiod if (length < maxlen)
15993d8817e4Smiod (hdr->ar_name)[length] = ar_padchar (abfd);
16003d8817e4Smiod }
16013d8817e4Smiod
16023d8817e4Smiod /* Store name into ar header. Truncates the name to fit.
16033d8817e4Smiod 1> strip pathname to be just the basename.
16043d8817e4Smiod 2> if it's short enuf to fit, stuff it in.
16053d8817e4Smiod 3> If it doesn't end with .o, truncate it to fit
16063d8817e4Smiod 4> truncate it before the .o, append .o, stuff THAT in. */
16073d8817e4Smiod
16083d8817e4Smiod /* This is what gnu ar does. It's better but incompatible with the
16093d8817e4Smiod bsd ar. */
16103d8817e4Smiod
16113d8817e4Smiod void
bfd_gnu_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)16123d8817e4Smiod bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
16133d8817e4Smiod {
16143d8817e4Smiod struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
16153d8817e4Smiod size_t length;
16163d8817e4Smiod const char *filename = strrchr (pathname, '/');
16173d8817e4Smiod size_t maxlen = ar_maxnamelen (abfd);
16183d8817e4Smiod
16193d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
16203d8817e4Smiod {
16213d8817e4Smiod /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
16223d8817e4Smiod char *bslash = strrchr (pathname, '\\');
16233d8817e4Smiod if (filename == NULL || (bslash != NULL && bslash > filename))
16243d8817e4Smiod filename = bslash;
16253d8817e4Smiod if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
16263d8817e4Smiod filename = pathname + 1;
16273d8817e4Smiod }
16283d8817e4Smiod #endif
16293d8817e4Smiod
16303d8817e4Smiod if (filename == NULL)
16313d8817e4Smiod filename = pathname;
16323d8817e4Smiod else
16333d8817e4Smiod ++filename;
16343d8817e4Smiod
16353d8817e4Smiod length = strlen (filename);
16363d8817e4Smiod
16373d8817e4Smiod if (length <= maxlen)
16383d8817e4Smiod memcpy (hdr->ar_name, filename, length);
16393d8817e4Smiod else
16403d8817e4Smiod { /* pathname: meet procrustes */
16413d8817e4Smiod memcpy (hdr->ar_name, filename, maxlen);
16423d8817e4Smiod if ((filename[length - 2] == '.') && (filename[length - 1] == 'o'))
16433d8817e4Smiod {
16443d8817e4Smiod hdr->ar_name[maxlen - 2] = '.';
16453d8817e4Smiod hdr->ar_name[maxlen - 1] = 'o';
16463d8817e4Smiod }
16473d8817e4Smiod length = maxlen;
16483d8817e4Smiod }
16493d8817e4Smiod
16503d8817e4Smiod if (length < 16)
16513d8817e4Smiod (hdr->ar_name)[length] = ar_padchar (abfd);
16523d8817e4Smiod }
16533d8817e4Smiod
16543d8817e4Smiod /* The BFD is open for write and has its format set to bfd_archive. */
16553d8817e4Smiod
16563d8817e4Smiod bfd_boolean
_bfd_write_archive_contents(bfd * arch)16573d8817e4Smiod _bfd_write_archive_contents (bfd *arch)
16583d8817e4Smiod {
16593d8817e4Smiod bfd *current;
16603d8817e4Smiod char *etable = NULL;
16613d8817e4Smiod bfd_size_type elength = 0;
16623d8817e4Smiod const char *ename = NULL;
16633d8817e4Smiod bfd_boolean makemap = bfd_has_map (arch);
16643d8817e4Smiod /* If no .o's, don't bother to make a map. */
16653d8817e4Smiod bfd_boolean hasobjects = FALSE;
16663d8817e4Smiod bfd_size_type wrote;
16673d8817e4Smiod int tries;
16683d8817e4Smiod
16693d8817e4Smiod /* Verify the viability of all entries; if any of them live in the
16703d8817e4Smiod filesystem (as opposed to living in an archive open for input)
16713d8817e4Smiod then construct a fresh ar_hdr for them. */
16723d8817e4Smiod for (current = arch->archive_head; current; current = current->next)
16733d8817e4Smiod {
16743d8817e4Smiod /* This check is checking the bfds for the objects we're reading
16753d8817e4Smiod from (which are usually either an object file or archive on
16763d8817e4Smiod disk), not the archive entries we're writing to. We don't
16773d8817e4Smiod actually create bfds for the archive members, we just copy
16783d8817e4Smiod them byte-wise when we write out the archive. */
16793d8817e4Smiod if (bfd_write_p (current))
16803d8817e4Smiod {
16813d8817e4Smiod bfd_set_error (bfd_error_invalid_operation);
16823d8817e4Smiod return FALSE;
16833d8817e4Smiod }
16843d8817e4Smiod if (!current->arelt_data)
16853d8817e4Smiod {
16863d8817e4Smiod current->arelt_data =
16873d8817e4Smiod bfd_ar_hdr_from_filesystem (arch, current->filename, current);
16883d8817e4Smiod if (!current->arelt_data)
16893d8817e4Smiod return FALSE;
16903d8817e4Smiod
16913d8817e4Smiod /* Put in the file name. */
16923d8817e4Smiod BFD_SEND (arch, _bfd_truncate_arname,
16933d8817e4Smiod (arch, current->filename, (char *) arch_hdr (current)));
16943d8817e4Smiod }
16953d8817e4Smiod
16963d8817e4Smiod if (makemap && ! hasobjects)
16973d8817e4Smiod { /* Don't bother if we won't make a map! */
16983d8817e4Smiod if ((bfd_check_format (current, bfd_object)))
16993d8817e4Smiod hasobjects = TRUE;
17003d8817e4Smiod }
17013d8817e4Smiod }
17023d8817e4Smiod
17033d8817e4Smiod if (!BFD_SEND (arch, _bfd_construct_extended_name_table,
17043d8817e4Smiod (arch, &etable, &elength, &ename)))
17053d8817e4Smiod return FALSE;
17063d8817e4Smiod
17073d8817e4Smiod if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0)
17083d8817e4Smiod return FALSE;
17093d8817e4Smiod wrote = bfd_bwrite (ARMAG, SARMAG, arch);
17103d8817e4Smiod if (wrote != SARMAG)
17113d8817e4Smiod return FALSE;
17123d8817e4Smiod
17133d8817e4Smiod if (makemap && hasobjects)
17143d8817e4Smiod {
17153d8817e4Smiod if (! _bfd_compute_and_write_armap (arch, (unsigned int) elength))
17163d8817e4Smiod return FALSE;
17173d8817e4Smiod }
17183d8817e4Smiod
17193d8817e4Smiod if (elength != 0)
17203d8817e4Smiod {
17213d8817e4Smiod struct ar_hdr hdr;
17223d8817e4Smiod
17233d8817e4Smiod memset (&hdr, ' ', sizeof (struct ar_hdr));
17243d8817e4Smiod memcpy (hdr.ar_name, ename, strlen (ename));
17253d8817e4Smiod /* Round size up to even number in archive header. */
17263d8817e4Smiod _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
17273d8817e4Smiod (elength + 1) & ~(bfd_size_type) 1);
17283d8817e4Smiod memcpy (hdr.ar_fmag, ARFMAG, 2);
17293d8817e4Smiod if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
17303d8817e4Smiod != sizeof (struct ar_hdr))
17313d8817e4Smiod || bfd_bwrite (etable, elength, arch) != elength)
17323d8817e4Smiod return FALSE;
17333d8817e4Smiod if ((elength % 2) == 1)
17343d8817e4Smiod {
17353d8817e4Smiod if (bfd_bwrite ("\012", 1, arch) != 1)
17363d8817e4Smiod return FALSE;
17373d8817e4Smiod }
17383d8817e4Smiod }
17393d8817e4Smiod
17403d8817e4Smiod for (current = arch->archive_head; current; current = current->next)
17413d8817e4Smiod {
17423d8817e4Smiod char buffer[DEFAULT_BUFFERSIZE];
17433d8817e4Smiod unsigned int remaining = arelt_size (current);
17443d8817e4Smiod struct ar_hdr *hdr = arch_hdr (current);
17453d8817e4Smiod
17463d8817e4Smiod /* Write ar header. */
17473d8817e4Smiod if (bfd_bwrite (hdr, sizeof (*hdr), arch)
17483d8817e4Smiod != sizeof (*hdr))
17493d8817e4Smiod return FALSE;
17503d8817e4Smiod if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
17513d8817e4Smiod return FALSE;
17523d8817e4Smiod while (remaining)
17533d8817e4Smiod {
17543d8817e4Smiod unsigned int amt = DEFAULT_BUFFERSIZE;
17553d8817e4Smiod if (amt > remaining)
17563d8817e4Smiod amt = remaining;
17573d8817e4Smiod errno = 0;
17583d8817e4Smiod if (bfd_bread (buffer, amt, current) != amt)
17593d8817e4Smiod {
17603d8817e4Smiod if (bfd_get_error () != bfd_error_system_call)
17613d8817e4Smiod bfd_set_error (bfd_error_malformed_archive);
17623d8817e4Smiod return FALSE;
17633d8817e4Smiod }
17643d8817e4Smiod if (bfd_bwrite (buffer, amt, arch) != amt)
17653d8817e4Smiod return FALSE;
17663d8817e4Smiod remaining -= amt;
17673d8817e4Smiod }
17683d8817e4Smiod if ((arelt_size (current) % 2) == 1)
17693d8817e4Smiod {
17703d8817e4Smiod if (bfd_bwrite ("\012", 1, arch) != 1)
17713d8817e4Smiod return FALSE;
17723d8817e4Smiod }
17733d8817e4Smiod }
17743d8817e4Smiod
17753d8817e4Smiod if (makemap && hasobjects)
17763d8817e4Smiod {
17773d8817e4Smiod /* Verify the timestamp in the archive file. If it would not be
17783d8817e4Smiod accepted by the linker, rewrite it until it would be. If
17793d8817e4Smiod anything odd happens, break out and just return. (The
17803d8817e4Smiod Berkeley linker checks the timestamp and refuses to read the
17813d8817e4Smiod table-of-contents if it is >60 seconds less than the file's
17823d8817e4Smiod modified-time. That painful hack requires this painful hack. */
17833d8817e4Smiod tries = 1;
17843d8817e4Smiod do
17853d8817e4Smiod {
17863d8817e4Smiod if (bfd_update_armap_timestamp (arch))
17873d8817e4Smiod break;
17883d8817e4Smiod (*_bfd_error_handler)
17893d8817e4Smiod (_("Warning: writing archive was slow: rewriting timestamp\n"));
17903d8817e4Smiod }
17913d8817e4Smiod while (++tries < 6);
17923d8817e4Smiod }
17933d8817e4Smiod
17943d8817e4Smiod return TRUE;
17953d8817e4Smiod }
17963d8817e4Smiod
17973d8817e4Smiod /* Note that the namidx for the first symbol is 0. */
17983d8817e4Smiod
17993d8817e4Smiod bfd_boolean
_bfd_compute_and_write_armap(bfd * arch,unsigned int elength)18003d8817e4Smiod _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
18013d8817e4Smiod {
18023d8817e4Smiod char *first_name = NULL;
18033d8817e4Smiod bfd *current;
18043d8817e4Smiod file_ptr elt_no = 0;
18053d8817e4Smiod struct orl *map = NULL;
18063d8817e4Smiod unsigned int orl_max = 1024; /* Fine initial default. */
18073d8817e4Smiod unsigned int orl_count = 0;
18083d8817e4Smiod int stridx = 0;
18093d8817e4Smiod asymbol **syms = NULL;
18103d8817e4Smiod long syms_max = 0;
18113d8817e4Smiod bfd_boolean ret;
18123d8817e4Smiod bfd_size_type amt;
18133d8817e4Smiod
18143d8817e4Smiod /* Dunno if this is the best place for this info... */
18153d8817e4Smiod if (elength != 0)
18163d8817e4Smiod elength += sizeof (struct ar_hdr);
18173d8817e4Smiod elength += elength % 2;
18183d8817e4Smiod
18193d8817e4Smiod amt = orl_max * sizeof (struct orl);
18203d8817e4Smiod map = bfd_malloc (amt);
18213d8817e4Smiod if (map == NULL)
18223d8817e4Smiod goto error_return;
18233d8817e4Smiod
18243d8817e4Smiod /* We put the symbol names on the arch objalloc, and then discard
18253d8817e4Smiod them when done. */
18263d8817e4Smiod first_name = bfd_alloc (arch, 1);
18273d8817e4Smiod if (first_name == NULL)
18283d8817e4Smiod goto error_return;
18293d8817e4Smiod
18303d8817e4Smiod /* Drop all the files called __.SYMDEF, we're going to make our own. */
18313d8817e4Smiod while (arch->archive_head &&
18323d8817e4Smiod strcmp (arch->archive_head->filename, "__.SYMDEF") == 0)
18333d8817e4Smiod arch->archive_head = arch->archive_head->next;
18343d8817e4Smiod
18353d8817e4Smiod /* Map over each element. */
18363d8817e4Smiod for (current = arch->archive_head;
18373d8817e4Smiod current != NULL;
18383d8817e4Smiod current = current->next, elt_no++)
18393d8817e4Smiod {
18403d8817e4Smiod if (bfd_check_format (current, bfd_object)
18413d8817e4Smiod && (bfd_get_file_flags (current) & HAS_SYMS) != 0)
18423d8817e4Smiod {
18433d8817e4Smiod long storage;
18443d8817e4Smiod long symcount;
18453d8817e4Smiod long src_count;
18463d8817e4Smiod
18473d8817e4Smiod storage = bfd_get_symtab_upper_bound (current);
18483d8817e4Smiod if (storage < 0)
18493d8817e4Smiod goto error_return;
18503d8817e4Smiod
18513d8817e4Smiod if (storage != 0)
18523d8817e4Smiod {
18533d8817e4Smiod if (storage > syms_max)
18543d8817e4Smiod {
18553d8817e4Smiod if (syms_max > 0)
18563d8817e4Smiod free (syms);
18573d8817e4Smiod syms_max = storage;
18583d8817e4Smiod syms = bfd_malloc (syms_max);
18593d8817e4Smiod if (syms == NULL)
18603d8817e4Smiod goto error_return;
18613d8817e4Smiod }
18623d8817e4Smiod symcount = bfd_canonicalize_symtab (current, syms);
18633d8817e4Smiod if (symcount < 0)
18643d8817e4Smiod goto error_return;
18653d8817e4Smiod
18663d8817e4Smiod /* Now map over all the symbols, picking out the ones we
18673d8817e4Smiod want. */
18683d8817e4Smiod for (src_count = 0; src_count < symcount; src_count++)
18693d8817e4Smiod {
18703d8817e4Smiod flagword flags = (syms[src_count])->flags;
18713d8817e4Smiod asection *sec = syms[src_count]->section;
18723d8817e4Smiod
18733d8817e4Smiod if ((flags & BSF_GLOBAL ||
18743d8817e4Smiod flags & BSF_WEAK ||
18753d8817e4Smiod flags & BSF_INDIRECT ||
18763d8817e4Smiod bfd_is_com_section (sec))
18773d8817e4Smiod && ! bfd_is_und_section (sec))
18783d8817e4Smiod {
18793d8817e4Smiod bfd_size_type namelen;
18803d8817e4Smiod struct orl *new_map;
18813d8817e4Smiod
18823d8817e4Smiod /* This symbol will go into the archive header. */
18833d8817e4Smiod if (orl_count == orl_max)
18843d8817e4Smiod {
18853d8817e4Smiod orl_max *= 2;
18863d8817e4Smiod amt = orl_max * sizeof (struct orl);
18873d8817e4Smiod new_map = bfd_realloc (map, amt);
18883d8817e4Smiod if (new_map == NULL)
18893d8817e4Smiod goto error_return;
18903d8817e4Smiod
18913d8817e4Smiod map = new_map;
18923d8817e4Smiod }
18933d8817e4Smiod
18943d8817e4Smiod namelen = strlen (syms[src_count]->name);
18953d8817e4Smiod amt = sizeof (char *);
18963d8817e4Smiod map[orl_count].name = bfd_alloc (arch, amt);
18973d8817e4Smiod if (map[orl_count].name == NULL)
18983d8817e4Smiod goto error_return;
18993d8817e4Smiod *(map[orl_count].name) = bfd_alloc (arch, namelen + 1);
19003d8817e4Smiod if (*(map[orl_count].name) == NULL)
19013d8817e4Smiod goto error_return;
19023d8817e4Smiod strcpy (*(map[orl_count].name), syms[src_count]->name);
19033d8817e4Smiod map[orl_count].u.abfd = current;
19043d8817e4Smiod map[orl_count].namidx = stridx;
19053d8817e4Smiod
19063d8817e4Smiod stridx += namelen + 1;
19073d8817e4Smiod ++orl_count;
19083d8817e4Smiod }
19093d8817e4Smiod }
19103d8817e4Smiod }
19113d8817e4Smiod
19123d8817e4Smiod /* Now ask the BFD to free up any cached information, so we
19133d8817e4Smiod don't fill all of memory with symbol tables. */
19143d8817e4Smiod if (! bfd_free_cached_info (current))
19153d8817e4Smiod goto error_return;
19163d8817e4Smiod }
19173d8817e4Smiod }
19183d8817e4Smiod
19193d8817e4Smiod /* OK, now we have collected all the data, let's write them out. */
19203d8817e4Smiod ret = BFD_SEND (arch, write_armap,
19213d8817e4Smiod (arch, elength, map, orl_count, stridx));
19223d8817e4Smiod
19233d8817e4Smiod if (syms_max > 0)
19243d8817e4Smiod free (syms);
19253d8817e4Smiod if (map != NULL)
19263d8817e4Smiod free (map);
19273d8817e4Smiod if (first_name != NULL)
19283d8817e4Smiod bfd_release (arch, first_name);
19293d8817e4Smiod
19303d8817e4Smiod return ret;
19313d8817e4Smiod
19323d8817e4Smiod error_return:
19333d8817e4Smiod if (syms_max > 0)
19343d8817e4Smiod free (syms);
19353d8817e4Smiod if (map != NULL)
19363d8817e4Smiod free (map);
19373d8817e4Smiod if (first_name != NULL)
19383d8817e4Smiod bfd_release (arch, first_name);
19393d8817e4Smiod
19403d8817e4Smiod return FALSE;
19413d8817e4Smiod }
19423d8817e4Smiod
19433d8817e4Smiod bfd_boolean
bsd_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int orl_count,int stridx)19443d8817e4Smiod bsd_write_armap (bfd *arch,
19453d8817e4Smiod unsigned int elength,
19463d8817e4Smiod struct orl *map,
19473d8817e4Smiod unsigned int orl_count,
19483d8817e4Smiod int stridx)
19493d8817e4Smiod {
19503d8817e4Smiod int padit = stridx & 1;
19513d8817e4Smiod unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE;
19523d8817e4Smiod unsigned int stringsize = stridx + padit;
19533d8817e4Smiod /* Include 8 bytes to store ranlibsize and stringsize in output. */
19543d8817e4Smiod unsigned int mapsize = ranlibsize + stringsize + 8;
19553d8817e4Smiod file_ptr firstreal;
19563d8817e4Smiod bfd *current = arch->archive_head;
19573d8817e4Smiod bfd *last_elt = current; /* Last element arch seen. */
19583d8817e4Smiod bfd_byte temp[4];
19593d8817e4Smiod unsigned int count;
19603d8817e4Smiod struct ar_hdr hdr;
19613d8817e4Smiod struct stat statbuf;
1962*314e8fdfSguenther long int uid, gid;
19633d8817e4Smiod
19643d8817e4Smiod firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
19653d8817e4Smiod
19663d8817e4Smiod stat (arch->filename, &statbuf);
19673d8817e4Smiod memset (&hdr, ' ', sizeof (struct ar_hdr));
19683d8817e4Smiod memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG));
19693d8817e4Smiod /* Remember the timestamp, to keep it holy. But fudge it a little. */
19703d8817e4Smiod bfd_ardata (arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET;
19713d8817e4Smiod bfd_ardata (arch)->armap_datepos = (SARMAG
19723d8817e4Smiod + offsetof (struct ar_hdr, ar_date[0]));
197304a47612Sguenther _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
19743d8817e4Smiod bfd_ardata (arch)->armap_timestamp);
1975*314e8fdfSguenther if ((arch->flags & BFD_DETERMINISTIC) != 0)
1976*314e8fdfSguenther uid = gid = 0;
1977*314e8fdfSguenther else
1978*314e8fdfSguenther {
1979*314e8fdfSguenther uid = getuid ();
1980*314e8fdfSguenther gid = getgid ();
1981*314e8fdfSguenther }
1982*314e8fdfSguenther _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid);
1983*314e8fdfSguenther _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid);
19843d8817e4Smiod _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize);
19853d8817e4Smiod memcpy (hdr.ar_fmag, ARFMAG, 2);
19863d8817e4Smiod if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
19873d8817e4Smiod != sizeof (struct ar_hdr))
19883d8817e4Smiod return FALSE;
19893d8817e4Smiod H_PUT_32 (arch, ranlibsize, temp);
19903d8817e4Smiod if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp))
19913d8817e4Smiod return FALSE;
19923d8817e4Smiod
19933d8817e4Smiod for (count = 0; count < orl_count; count++)
19943d8817e4Smiod {
19953d8817e4Smiod bfd_byte buf[BSD_SYMDEF_SIZE];
19963d8817e4Smiod
19973d8817e4Smiod if (map[count].u.abfd != last_elt)
19983d8817e4Smiod {
19993d8817e4Smiod do
20003d8817e4Smiod {
20013d8817e4Smiod firstreal += arelt_size (current) + sizeof (struct ar_hdr);
20023d8817e4Smiod firstreal += firstreal % 2;
20033d8817e4Smiod current = current->next;
20043d8817e4Smiod }
20053d8817e4Smiod while (current != map[count].u.abfd);
20063d8817e4Smiod }
20073d8817e4Smiod
20083d8817e4Smiod last_elt = current;
20093d8817e4Smiod H_PUT_32 (arch, map[count].namidx, buf);
20103d8817e4Smiod H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE);
20113d8817e4Smiod if (bfd_bwrite (buf, BSD_SYMDEF_SIZE, arch)
20123d8817e4Smiod != BSD_SYMDEF_SIZE)
20133d8817e4Smiod return FALSE;
20143d8817e4Smiod }
20153d8817e4Smiod
20163d8817e4Smiod /* Now write the strings themselves. */
20173d8817e4Smiod H_PUT_32 (arch, stringsize, temp);
20183d8817e4Smiod if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp))
20193d8817e4Smiod return FALSE;
20203d8817e4Smiod for (count = 0; count < orl_count; count++)
20213d8817e4Smiod {
20223d8817e4Smiod size_t len = strlen (*map[count].name) + 1;
20233d8817e4Smiod
20243d8817e4Smiod if (bfd_bwrite (*map[count].name, len, arch) != len)
20253d8817e4Smiod return FALSE;
20263d8817e4Smiod }
20273d8817e4Smiod
20283d8817e4Smiod /* The spec sez this should be a newline. But in order to be
20293d8817e4Smiod bug-compatible for sun's ar we use a null. */
20303d8817e4Smiod if (padit)
20313d8817e4Smiod {
20323d8817e4Smiod if (bfd_bwrite ("", 1, arch) != 1)
20333d8817e4Smiod return FALSE;
20343d8817e4Smiod }
20353d8817e4Smiod
20363d8817e4Smiod return TRUE;
20373d8817e4Smiod }
20383d8817e4Smiod
20393d8817e4Smiod /* At the end of archive file handling, update the timestamp in the
20403d8817e4Smiod file, so the linker will accept it.
20413d8817e4Smiod
20423d8817e4Smiod Return TRUE if the timestamp was OK, or an unusual problem happened.
20433d8817e4Smiod Return FALSE if we updated the timestamp. */
20443d8817e4Smiod
20453d8817e4Smiod bfd_boolean
_bfd_archive_bsd_update_armap_timestamp(bfd * arch)20463d8817e4Smiod _bfd_archive_bsd_update_armap_timestamp (bfd *arch)
20473d8817e4Smiod {
20483d8817e4Smiod struct stat archstat;
20493d8817e4Smiod struct ar_hdr hdr;
20503d8817e4Smiod
20513d8817e4Smiod /* Flush writes, get last-write timestamp from file, and compare it
20523d8817e4Smiod to the timestamp IN the file. */
20533d8817e4Smiod bfd_flush (arch);
20543d8817e4Smiod if (bfd_stat (arch, &archstat) == -1)
20553d8817e4Smiod {
20563d8817e4Smiod bfd_perror (_("Reading archive file mod timestamp"));
20573d8817e4Smiod
20583d8817e4Smiod /* Can't read mod time for some reason. */
20593d8817e4Smiod return TRUE;
20603d8817e4Smiod }
20613d8817e4Smiod if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp)
20623d8817e4Smiod /* OK by the linker's rules. */
20633d8817e4Smiod return TRUE;
20643d8817e4Smiod
20653d8817e4Smiod /* Update the timestamp. */
20663d8817e4Smiod bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET;
20673d8817e4Smiod
20683d8817e4Smiod /* Prepare an ASCII version suitable for writing. */
20693d8817e4Smiod memset (hdr.ar_date, ' ', sizeof (hdr.ar_date));
207004a47612Sguenther _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
20713d8817e4Smiod bfd_ardata (arch)->armap_timestamp);
20723d8817e4Smiod
20733d8817e4Smiod /* Write it into the file. */
20743d8817e4Smiod bfd_ardata (arch)->armap_datepos = (SARMAG
20753d8817e4Smiod + offsetof (struct ar_hdr, ar_date[0]));
20763d8817e4Smiod if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0
20773d8817e4Smiod || (bfd_bwrite (hdr.ar_date, sizeof (hdr.ar_date), arch)
20783d8817e4Smiod != sizeof (hdr.ar_date)))
20793d8817e4Smiod {
20803d8817e4Smiod bfd_perror (_("Writing updated armap timestamp"));
20813d8817e4Smiod
20823d8817e4Smiod /* Some error while writing. */
20833d8817e4Smiod return TRUE;
20843d8817e4Smiod }
20853d8817e4Smiod
20863d8817e4Smiod /* We updated the timestamp successfully. */
20873d8817e4Smiod return FALSE;
20883d8817e4Smiod }
20893d8817e4Smiod
20903d8817e4Smiod /* A coff armap looks like :
20913d8817e4Smiod lARMAG
20923d8817e4Smiod struct ar_hdr with name = '/'
20933d8817e4Smiod number of symbols
20943d8817e4Smiod offset of file for symbol 0
20953d8817e4Smiod offset of file for symbol 1
20963d8817e4Smiod
20973d8817e4Smiod offset of file for symbol n-1
20983d8817e4Smiod symbol name 0
20993d8817e4Smiod symbol name 1
21003d8817e4Smiod
21013d8817e4Smiod symbol name n-1 */
21023d8817e4Smiod
21033d8817e4Smiod bfd_boolean
coff_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int symbol_count,int stridx)21043d8817e4Smiod coff_write_armap (bfd *arch,
21053d8817e4Smiod unsigned int elength,
21063d8817e4Smiod struct orl *map,
21073d8817e4Smiod unsigned int symbol_count,
21083d8817e4Smiod int stridx)
21093d8817e4Smiod {
21103d8817e4Smiod /* The size of the ranlib is the number of exported symbols in the
21113d8817e4Smiod archive * the number of bytes in an int, + an int for the count. */
21123d8817e4Smiod unsigned int ranlibsize = (symbol_count * 4) + 4;
21133d8817e4Smiod unsigned int stringsize = stridx;
21143d8817e4Smiod unsigned int mapsize = stringsize + ranlibsize;
21153d8817e4Smiod unsigned int archive_member_file_ptr;
21163d8817e4Smiod bfd *current = arch->archive_head;
21173d8817e4Smiod unsigned int count;
21183d8817e4Smiod struct ar_hdr hdr;
21193d8817e4Smiod int padit = mapsize & 1;
21203d8817e4Smiod
21213d8817e4Smiod if (padit)
21223d8817e4Smiod mapsize++;
21233d8817e4Smiod
21243d8817e4Smiod /* Work out where the first object file will go in the archive. */
21253d8817e4Smiod archive_member_file_ptr = (mapsize
21263d8817e4Smiod + elength
21273d8817e4Smiod + sizeof (struct ar_hdr)
21283d8817e4Smiod + SARMAG);
21293d8817e4Smiod
21303d8817e4Smiod memset (&hdr, ' ', sizeof (struct ar_hdr));
21313d8817e4Smiod hdr.ar_name[0] = '/';
21323d8817e4Smiod _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
21333d8817e4Smiod mapsize);
213404a47612Sguenther _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
21353d8817e4Smiod time (NULL));
21363d8817e4Smiod /* This, at least, is what Intel coff sets the values to. */
21373d8817e4Smiod _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
21383d8817e4Smiod _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);
21393d8817e4Smiod _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0);
21403d8817e4Smiod memcpy (hdr.ar_fmag, ARFMAG, 2);
21413d8817e4Smiod
21423d8817e4Smiod /* Write the ar header for this item and the number of symbols. */
21433d8817e4Smiod if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
21443d8817e4Smiod != sizeof (struct ar_hdr))
21453d8817e4Smiod return FALSE;
21463d8817e4Smiod
21473d8817e4Smiod if (!bfd_write_bigendian_4byte_int (arch, symbol_count))
21483d8817e4Smiod return FALSE;
21493d8817e4Smiod
21503d8817e4Smiod /* Two passes, first write the file offsets for each symbol -
21513d8817e4Smiod remembering that each offset is on a two byte boundary. */
21523d8817e4Smiod
21533d8817e4Smiod /* Write out the file offset for the file associated with each
21543d8817e4Smiod symbol, and remember to keep the offsets padded out. */
21553d8817e4Smiod
21563d8817e4Smiod current = arch->archive_head;
21573d8817e4Smiod count = 0;
21583d8817e4Smiod while (current != NULL && count < symbol_count)
21593d8817e4Smiod {
21603d8817e4Smiod /* For each symbol which is used defined in this object, write
21613d8817e4Smiod out the object file's address in the archive. */
21623d8817e4Smiod
21633d8817e4Smiod while (count < symbol_count && map[count].u.abfd == current)
21643d8817e4Smiod {
21653d8817e4Smiod if (!bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr))
21663d8817e4Smiod return FALSE;
21673d8817e4Smiod count++;
21683d8817e4Smiod }
21693d8817e4Smiod /* Add size of this archive entry. */
21703d8817e4Smiod archive_member_file_ptr += arelt_size (current) + sizeof (struct ar_hdr);
21713d8817e4Smiod /* Remember aboout the even alignment. */
21723d8817e4Smiod archive_member_file_ptr += archive_member_file_ptr % 2;
21733d8817e4Smiod current = current->next;
21743d8817e4Smiod }
21753d8817e4Smiod
21763d8817e4Smiod /* Now write the strings themselves. */
21773d8817e4Smiod for (count = 0; count < symbol_count; count++)
21783d8817e4Smiod {
21793d8817e4Smiod size_t len = strlen (*map[count].name) + 1;
21803d8817e4Smiod
21813d8817e4Smiod if (bfd_bwrite (*map[count].name, len, arch) != len)
21823d8817e4Smiod return FALSE;
21833d8817e4Smiod }
21843d8817e4Smiod
21853d8817e4Smiod /* The spec sez this should be a newline. But in order to be
21863d8817e4Smiod bug-compatible for arc960 we use a null. */
21873d8817e4Smiod if (padit)
21883d8817e4Smiod {
21893d8817e4Smiod if (bfd_bwrite ("", 1, arch) != 1)
21903d8817e4Smiod return FALSE;
21913d8817e4Smiod }
21923d8817e4Smiod
21933d8817e4Smiod return TRUE;
21943d8817e4Smiod }
2195