From: Nick Clifton Date: Fri, 28 Mar 2008 06:49:44 +0000 (+0000) Subject: Add support for thin archives. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a8da6403829d6f87867da6a737dfdaa736a37dfa;p=binutils-gdb.git Add support for thin archives. * bfd/archive.c (_bfd_find_nested_archive): New function. (get_extended_arelt_filename): Add origin parameter. (_bfd_generic_read_ar_hdr_mag): Deal with extended name combined with a file offset. (append_relative_path): New function. (_bfd_get_elt_at_filepos): Deal with external members and nested archives. (bfd_generic_openr_next_archived_file): Thin archives. (bfd_generic_archive_p): Recognize new magic string. (adjust_relative_path): New function. (_bfd_construct_extended_name_table): Construct extended names for thin archive members. (_bfd_write_archive_contents): Emit new magic string, skip copying files for thin archives. * bfd/bfd-in.h (bfd_is_thin_archive): New macro. * bfd/bfd.c (struct bfd): New fields for thin archives. * bfd/libbfd-in.h (struct areltdata): New field for thin archives. * bfd/opncls.c (bfd_close): Delete BFDs for nested archives. * binutils/ar.c (make_thin_archive): New global flag. (map_over_members): Deal with full pathnames in thin archives. (usage, main): Add 'T' option for building thin archives. (replace_members): Pass thin archive flag to ar_emul_append. * binutils/arsup.c (ar_open): Initialize new flag. * binutils/binemul.c (ar_emul_append): Add new parameter for flattening nested archives. (do_ar_emul_default_append): New function. (ar_emul_default_append): Factored out recursive code. * binutils/binemul.h (ar_emul_default_append): Add new parameter. (struct bin_emulation_xfer_struct): New parameter for ar_append. * binutils/dlltool.c (gen_lib_file): Initialize thin archive flag. * binutils/emul_aix.c (ar_emul_aix_internal): Add new flatten parameter, currently unimplemented. All callers changed. * binutils/objcopy.c (copy_archive): Preserve thin archive flag. * binutils/doc/binutils.texi: Update ar documentation. * binutils/testsuite/binutils-all/ar.exp: Add thin archive tests. * include/aout/ar.h (ARMAGT): New magic string for thin archives. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 55514b43c34..063a304e55f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,25 @@ +2008-03-27 Cary Coutant + + Add support for thin archives. + * archive.c (_bfd_find_nested_archive): New function. + (get_extended_arelt_filename): Add origin parameter. + (_bfd_generic_read_ar_hdr_mag): Deal with extended name + combined with a file offset. + (append_relative_path): New function. + (_bfd_get_elt_at_filepos): Deal with external members and + nested archives. + (bfd_generic_openr_next_archived_file): Thin archives. + (bfd_generic_archive_p): Recognize new magic string. + (adjust_relative_path): New function. + (_bfd_construct_extended_name_table): Construct extended + names for thin archive members. + (_bfd_write_archive_contents): Emit new magic string, skip + copying files for thin archives. + * bfd-in.h (bfd_is_thin_archive): New macro. + * bfd.c (struct bfd): New fields for thin archives. + * libbfd-in.h (struct areltdata): New field for thin archives. + * opncls.c (bfd_close): Delete BFDs for nested archives. + 2008-03-25 Bernd Schmidt * elf32-bfin.c (bfin_final_link_relocate): New function, wrapper around diff --git a/bfd/archive.c b/bfd/archive.c index e080d3a301d..5389f7adcc5 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1,6 +1,6 @@ /* BFD back-end for archive files (libraries). Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. @@ -137,6 +137,7 @@ SUBSECTION #include "aout/ranlib.h" #include "safe-ctype.h" #include "hashtab.h" +#include "filenames.h" #ifndef errno extern int errno; @@ -157,7 +158,7 @@ struct ar_cache { #define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) -#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata(bfd)->arch_header) +#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header) void _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) @@ -326,24 +327,61 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) return TRUE; } +static bfd * +_bfd_find_nested_archive (bfd *arch_bfd, const char *filename) +{ + bfd *abfd; + + for (abfd = arch_bfd->nested_archives; + abfd != NULL; + abfd = abfd->archive_next) + { + if (strcmp (filename, abfd->filename) == 0) + return abfd; + } + abfd = bfd_openr (filename, NULL); + if (abfd) + { + abfd->archive_next = arch_bfd->nested_archives; + arch_bfd->nested_archives = abfd; + } + return abfd; +} + /* The name begins with space. Hence the rest of the name is an index into the string table. */ static char * -get_extended_arelt_filename (bfd *arch, const char *name) +get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) { unsigned long index = 0; + const char *endp; /* Should extract string so that I can guarantee not to overflow into the next region, but I'm too lazy. */ errno = 0; /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ - index = strtol (name + 1, NULL, 10); + index = strtol (name + 1, (char **) &endp, 10); if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size) { bfd_set_error (bfd_error_malformed_archive); return NULL; } + /* In a thin archive, a member of an archive-within-an-archive + will have the offset in the inner archive encoded here. */ + if (bfd_is_thin_archive (arch) && endp != NULL && *endp == ':') + { + file_ptr origin = strtol (endp + 1, NULL, 10); + + if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + *originp = origin; + } + else + *originp = 0; return bfd_ardata (arch)->extended_names + index; } @@ -376,6 +414,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) bfd_size_type namelen = 0; bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); char *allocptr = 0; + file_ptr origin = 0; if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr)) { @@ -407,7 +446,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL)) && bfd_ardata (abfd)->extended_names != NULL) { - filename = get_extended_arelt_filename (abfd, hdr.ar_name); + filename = get_extended_arelt_filename (abfd, hdr.ar_name, &origin); if (filename == NULL) return NULL; } @@ -476,6 +515,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) ared->arch_header = allocptr + sizeof (struct areltdata); memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr)); ared->parsed_size = parsed_size; + ared->origin = origin; if (filename != NULL) ared->filename = filename; @@ -491,6 +531,30 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) return ared; } +/* Append the relative pathname for a member of the thin archive + to the pathname of the directory containing the archive. */ + +static char * +append_relative_path (bfd *arch, char *elt_name) +{ + const char *arch_name = arch->filename; + const char *base_name = lbasename (arch_name); + size_t prefix_len; + char *filename; + + if (base_name == arch_name) + return elt_name; + + prefix_len = base_name - arch_name; + filename = bfd_alloc (arch, prefix_len + strlen (elt_name) + 1); + if (filename == NULL) + return NULL; + + strncpy (filename, arch_name, prefix_len); + strcpy (filename + prefix_len, elt_name); + return filename; +} + /* This is an internal function; it's mainly used when indexing through the archive symbol table, but also used to get the next element, since it handles the bookkeeping so nicely for us. */ @@ -500,6 +564,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) { struct areltdata *new_areldata; bfd *n_nfd; + char *filename; if (archive->my_archive) { @@ -517,21 +582,74 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL) return NULL; - n_nfd = _bfd_create_empty_archive_element_shell (archive); + filename = new_areldata->filename; + + if (bfd_is_thin_archive (archive)) + { + /* This is a proxy entry for an external file. */ + if (! IS_ABSOLUTE_PATH (filename)) + { + filename = append_relative_path (archive, filename); + if (filename == NULL) + return NULL; + } + + if (new_areldata->origin > 0) + { + /* This proxy entry refers to an element of a nested archive. + Locate the member of that archive and return a bfd for it. */ + bfd *ext_arch = _bfd_find_nested_archive (archive, filename); + + if (ext_arch == NULL + || ! bfd_check_format (ext_arch, bfd_archive)) + { + bfd_release (archive, new_areldata); + return NULL; + } + n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin); + if (n_nfd == NULL) + { + bfd_release (archive, new_areldata); + return NULL; + } + n_nfd->proxy_origin = bfd_tell (archive); + return n_nfd; + } + /* It's not an element of a nested archive; + open the external file as a bfd. */ + n_nfd = bfd_openr (filename, NULL); + } + else + { + n_nfd = _bfd_create_empty_archive_element_shell (archive); + } + if (n_nfd == NULL) { bfd_release (archive, new_areldata); return NULL; } - n_nfd->origin = bfd_tell (archive); + n_nfd->proxy_origin = bfd_tell (archive); + + if (bfd_is_thin_archive (archive)) + { + n_nfd->origin = 0; + } + else + { + n_nfd->origin = n_nfd->proxy_origin; + n_nfd->filename = filename; + } + n_nfd->arelt_data = new_areldata; - n_nfd->filename = new_areldata->filename; if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) return n_nfd; /* Huh? */ + /* FIXME: n_nfd isn't allocated in the archive's memory pool. + If we reach this point, I think bfd_release will abort. */ bfd_release (archive, n_nfd); bfd_release (archive, new_areldata); return NULL; @@ -568,8 +686,8 @@ DESCRIPTION bfd * bfd_openr_next_archived_file (bfd *archive, bfd *last_file) { - if ((bfd_get_format (archive) != bfd_archive) || - (archive->direction == write_direction)) + if ((bfd_get_format (archive) != bfd_archive) + || (archive->direction == write_direction)) { bfd_set_error (bfd_error_invalid_operation); return NULL; @@ -589,7 +707,9 @@ bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file) else { unsigned int size = arelt_size (last_file); - filestart = last_file->origin + size; + filestart = last_file->proxy_origin; + if (! bfd_is_thin_archive (archive)) + filestart += size; if (archive->my_archive) filestart -= archive->origin; /* Pad to an even boundary... @@ -615,8 +735,11 @@ bfd_generic_archive_p (bfd *abfd) return NULL; } - if (strncmp (armag, ARMAG, SARMAG) != 0 && - strncmp (armag, ARMAGB, SARMAG) != 0) + bfd_is_thin_archive (abfd) = (strncmp (armag, ARMAGT, SARMAG) == 0); + + if (strncmp (armag, ARMAG, SARMAG) != 0 + && strncmp (armag, ARMAGB, SARMAG) != 0 + && ! bfd_is_thin_archive (abfd)) return 0; tdata_hold = bfd_ardata (abfd); @@ -1110,7 +1233,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) char *limit = temp + namedata->parsed_size; for (; temp < limit; ++temp) { - if (*temp == '\012') + if (*temp == ARFMAG[0]) temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0'; if (*temp == '\\') *temp = '/'; @@ -1190,6 +1313,66 @@ normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file) } #endif +/* Adjust a relative path name based on the reference path. */ + +static const char * +adjust_relative_path (const char * path, const char * ref_path) +{ + static char *pathbuf = NULL; + static int pathbuf_len = 0; + const char *pathp = path; + const char *refp = ref_path; + int element_count = 0; + int len; + char *newp; + + /* Remove common leading path elements. */ + for (;;) + { + const char *e1 = pathp; + const char *e2 = refp; + + while (*e1 && ! IS_DIR_SEPARATOR (*e1)) + ++e1; + while (*e2 && ! IS_DIR_SEPARATOR (*e2)) + ++e2; + if (*e1 == '\0' || *e2 == '\0' || e1 - pathp != e2 - refp + || strncmp (pathp, refp, e1 - pathp) != 0) + break; + pathp = e1 + 1; + refp = e2 + 1; + } + + /* For each leading path element in the reference path, + insert "../" into the path. */ + for (; *refp; ++refp) + if (IS_DIR_SEPARATOR (*refp)) + ++element_count; + len = 3 * element_count + strlen (path) + 1; + + if (len > pathbuf_len) + { + if (pathbuf != NULL) + free (pathbuf); + pathbuf_len = 0; + pathbuf = bfd_malloc (len); + if (pathbuf == NULL) + return path; + pathbuf_len = len; + } + + newp = pathbuf; + while (element_count-- > 0) + { + /* FIXME: Support Windows style path separators as well. */ + strcpy (newp, "../"); + newp += 3; + } + strcpy (newp, pathp); + + return pathbuf; +} + /* Build a BFD style extended name table. */ bfd_boolean @@ -1232,8 +1415,11 @@ _bfd_construct_extended_name_table (bfd *abfd, bfd_size_type total_namelen = 0; bfd *current; char *strptr; + const char *last_filename; + long last_stroff; *tablen = 0; + last_filename = NULL; /* Figure out how long the table should be. */ for (current = abfd->archive_head; @@ -1243,6 +1429,42 @@ _bfd_construct_extended_name_table (bfd *abfd, const char *normal; unsigned int thislen; + if (bfd_is_thin_archive (abfd)) + { + const char *filename = current->filename; + + /* If the element being added is a member of another archive + (i.e., we are flattening), use the containing archive's name. */ + if (current->my_archive + && ! bfd_is_thin_archive (current->my_archive)) + filename = current->my_archive->filename; + + /* If the path is the same as the previous path seen, + reuse it. This can happen when flattening a thin + archive that contains other archives. */ + if (last_filename && strcmp (last_filename, filename) == 0) + continue; + + last_filename = filename; + + /* If the path is relative, adjust it relative to + the containing archive. */ + if (! IS_ABSOLUTE_PATH (filename) + && ! IS_ABSOLUTE_PATH (abfd->filename)) + normal = adjust_relative_path (filename, abfd->filename); + else + normal = filename; + + /* In a thin archive, always store the full pathname + in the extended name table. */ + total_namelen += strlen (normal) + 1; + if (trailing_slash) + /* Leave room for trailing slash. */ + ++total_namelen; + + continue; + } + normal = normalize (current, current->filename); if (normal == NULL) return FALSE; @@ -1290,38 +1512,85 @@ _bfd_construct_extended_name_table (bfd *abfd, *tablen = total_namelen; strptr = *tabloc; + last_filename = NULL; + last_stroff = 0; + for (current = abfd->archive_head; current != NULL; current = current->archive_next) { const char *normal; unsigned int thislen; - - normal = normalize (current, current->filename); - if (normal == NULL) - return FALSE; + long stroff; + const char *filename = current->filename; + + if (bfd_is_thin_archive (abfd)) + { + /* If the element being added is a member of another archive + (i.e., we are flattening), use the containing archive's name. */ + if (current->my_archive + && ! bfd_is_thin_archive (current->my_archive)) + filename = current->my_archive->filename; + /* If the path is the same as the previous path seen, + reuse it. This can happen when flattening a thin + archive that contains other archives. + If the path is relative, adjust it relative to + the containing archive. */ + if (last_filename && strcmp (last_filename, filename) == 0) + normal = last_filename; + else if (! IS_ABSOLUTE_PATH (filename) + && ! IS_ABSOLUTE_PATH (abfd->filename)) + normal = adjust_relative_path (filename, abfd->filename); + else + normal = filename; + } + else + { + normal = normalize (current, filename); + if (normal == NULL) + return FALSE; + } thislen = strlen (normal); - if (thislen > maxname) + if (thislen > maxname || bfd_is_thin_archive (abfd)) { /* Works for now; may need to be re-engineered if we encounter an oddball archive format and want to generalise this hack. */ struct ar_hdr *hdr = arch_hdr (current); - strcpy (strptr, normal); - if (! trailing_slash) - strptr[thislen] = '\012'; - else - { - strptr[thislen] = '/'; - strptr[thislen + 1] = '\012'; + if (normal == last_filename) + stroff = last_stroff; + else + { + strcpy (strptr, normal); + if (! trailing_slash) + strptr[thislen] = ARFMAG[0]; + else + { + strptr[thislen] = '/'; + strptr[thislen + 1] = ARFMAG[0]; + } + stroff = strptr - *tabloc; + last_stroff = stroff; } hdr->ar_name[0] = ar_padchar (current); - _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", - strptr - *tabloc); - strptr += thislen + 1; - if (trailing_slash) - ++strptr; + if (bfd_is_thin_archive (abfd) && current->origin > 0) + { + int len = snprintf (hdr->ar_name + 1, maxname - 1, "%-ld:", + stroff); + _bfd_ar_spacepad (hdr->ar_name + 1 + len, maxname - 1 - len, + "%-ld", + current->origin - sizeof (struct ar_hdr)); + } + else + _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff); + if (normal != last_filename) + { + strptr += thislen + 1; + if (trailing_slash) + ++strptr; + last_filename = filename; + } } } @@ -1593,6 +1862,7 @@ bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) { /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ char *bslash = strrchr (pathname, '\\'); + if (filename == NULL || (bslash != NULL && bslash > filename)) filename = bslash; if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':') @@ -1610,7 +1880,8 @@ bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) if (length <= maxlen) memcpy (hdr->ar_name, filename, length); else - { /* pathname: meet procrustes */ + { + /* pathname: meet procrustes. */ memcpy (hdr->ar_name, filename, maxlen); if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) { @@ -1638,6 +1909,7 @@ _bfd_write_archive_contents (bfd *arch) bfd_boolean hasobjects = FALSE; bfd_size_type wrote; int tries; + char *armag; /* Verify the viability of all entries; if any of them live in the filesystem (as opposed to living in an archive open for input) @@ -1681,7 +1953,10 @@ _bfd_write_archive_contents (bfd *arch) if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0) return FALSE; - wrote = bfd_bwrite (ARMAG, SARMAG, arch); + armag = ARMAG; + if (bfd_is_thin_archive (arch)) + armag = ARMAGT; + wrote = bfd_bwrite (armag, SARMAG, arch); if (wrote != SARMAG) return FALSE; @@ -1707,7 +1982,7 @@ _bfd_write_archive_contents (bfd *arch) return FALSE; if ((elength % 2) == 1) { - if (bfd_bwrite ("\012", 1, arch) != 1) + if (bfd_bwrite (ARFMAG, 1, arch) != 1) return FALSE; } } @@ -1724,11 +1999,15 @@ _bfd_write_archive_contents (bfd *arch) if (bfd_bwrite (hdr, sizeof (*hdr), arch) != sizeof (*hdr)) return FALSE; + if (bfd_is_thin_archive (arch)) + continue; if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto input_err; + while (remaining) { unsigned int amt = DEFAULT_BUFFERSIZE; + if (amt > remaining) amt = remaining; errno = 0; @@ -1742,9 +2021,10 @@ _bfd_write_archive_contents (bfd *arch) return FALSE; remaining -= amt; } + if ((arelt_size (current) % 2) == 1) { - if (bfd_bwrite ("\012", 1, arch) != 1) + if (bfd_bwrite (ARFMAG, 1, arch) != 1) return FALSE; } } @@ -1809,8 +2089,8 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) goto error_return; /* Drop all the files called __.SYMDEF, we're going to make our own. */ - while (arch->archive_head && - strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) + while (arch->archive_head + && strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) arch->archive_head = arch->archive_head->archive_next; /* Map over each element. */ @@ -1851,10 +2131,10 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) flagword flags = (syms[src_count])->flags; asection *sec = syms[src_count]->section; - if ((flags & BSF_GLOBAL || - flags & BSF_WEAK || - flags & BSF_INDIRECT || - bfd_is_com_section (sec)) + if ((flags & BSF_GLOBAL + || flags & BSF_WEAK + || flags & BSF_INDIRECT + || bfd_is_com_section (sec)) && ! bfd_is_und_section (sec)) { bfd_size_type namelen; @@ -2139,10 +2419,14 @@ coff_write_armap (bfd *arch, return FALSE; count++; } - /* Add size of this archive entry. */ - archive_member_file_ptr += arelt_size (current) + sizeof (struct ar_hdr); - /* Remember aboout the even alignment. */ - archive_member_file_ptr += archive_member_file_ptr % 2; + archive_member_file_ptr += sizeof (struct ar_hdr); + if (! bfd_is_thin_archive (arch)) + { + /* Add size of this archive entry. */ + archive_member_file_ptr += arelt_size (current); + /* Remember about the even alignment. */ + archive_member_file_ptr += archive_member_file_ptr % 2; + } current = current->archive_next; } diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index 1c11f6bbbfc..319c0df7bf0 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -499,6 +499,7 @@ extern void warn_deprecated (const char *, const char *, int, const char *); #define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) #define bfd_my_archive(abfd) ((abfd)->my_archive) #define bfd_has_map(abfd) ((abfd)->has_armap) +#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive) #define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) #define bfd_usrdata(abfd) ((abfd)->usrdata) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 4e13bef7d8f..88dc337b121 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -506,6 +506,7 @@ extern void warn_deprecated (const char *, const char *, int, const char *); #define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) #define bfd_my_archive(abfd) ((abfd)->my_archive) #define bfd_has_map(abfd) ((abfd)->has_armap) +#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive) #define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) #define bfd_usrdata(abfd) ((abfd)->usrdata) @@ -4659,6 +4660,13 @@ struct bfd origin, with origin set to 0 for non archive files. */ ufile_ptr origin; + /* The origin in the archive of the proxy entry. This will + normally be the same as origin, except for thin archives, + when it will contain the current offset of the proxy in the + thin archive rather than the offset of the bfd in its actual + container. */ + ufile_ptr proxy_origin; + /* A hash table for section names. */ struct bfd_hash_table section_htab; @@ -4692,6 +4700,8 @@ struct bfd struct bfd *my_archive; /* The containing archive BFD. */ struct bfd *archive_next; /* The next BFD in the archive. */ struct bfd *archive_head; /* The first BFD in the archive. */ + struct bfd *nested_archives; /* List of nested archive in a flattened + thin archive. */ /* A chain of BFD structures involved in a link. */ struct bfd *link_next; @@ -4774,6 +4784,9 @@ struct bfd /* Have archive map. */ unsigned int has_armap : 1; + + /* Set if this is a thin archive. */ + unsigned int is_thin_archive : 1; }; typedef enum bfd_error diff --git a/bfd/bfd.c b/bfd/bfd.c index ce7b3918d67..7e6e872feb5 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -150,6 +150,13 @@ CODE_FRAGMENT . origin, with origin set to 0 for non archive files. *} . ufile_ptr origin; . +. {* The origin in the archive of the proxy entry. This will +. normally be the same as origin, except for thin archives, +. when it will contain the current offset of the proxy in the +. thin archive rather than the offset of the bfd in its actual +. container. *} +. ufile_ptr proxy_origin; +. . {* A hash table for section names. *} . struct bfd_hash_table section_htab; . @@ -183,6 +190,8 @@ CODE_FRAGMENT . struct bfd *my_archive; {* The containing archive BFD. *} . struct bfd *archive_next; {* The next BFD in the archive. *} . struct bfd *archive_head; {* The first BFD in the archive. *} +. struct bfd *nested_archives; {* List of nested archive in a flattened +. thin archive. *} . . {* A chain of BFD structures involved in a link. *} . struct bfd *link_next; @@ -265,6 +274,9 @@ CODE_FRAGMENT . . {* Have archive map. *} . unsigned int has_armap : 1; +. +. {* Set if this is a thin archive. *} +. unsigned int is_thin_archive : 1; .}; . */ diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index f57d450a4fb..949a2d2dc74 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -91,6 +91,7 @@ struct areltdata { char * arch_header; /* it's actually a string */ unsigned int parsed_size; /* octets of filesize not including ar_hdr */ char *filename; /* null-terminated */ + file_ptr origin; /* for element of a thin archive */ }; #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index cfc364f2435..1b447204dd4 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -96,6 +96,7 @@ struct areltdata { char * arch_header; /* it's actually a string */ unsigned int parsed_size; /* octets of filesize not including ar_hdr */ char *filename; /* null-terminated */ + file_ptr origin; /* for element of a thin archive */ }; #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) diff --git a/bfd/opncls.c b/bfd/opncls.c index 47fef7036a2..2ceb77eb21a 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -647,6 +647,8 @@ bfd_boolean bfd_close (bfd *abfd) { bfd_boolean ret; + bfd *nbfd; + bfd *next; if (bfd_write_p (abfd)) { @@ -654,6 +656,13 @@ bfd_close (bfd *abfd) return FALSE; } + /* Close nested archives (if this bfd is a thin archive). */ + for (nbfd = abfd->nested_archives; nbfd; nbfd = next) + { + next = nbfd->archive_next; + bfd_close (nbfd); + } + if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) return FALSE; diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 30466fe5053..b0e140a4542 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,25 @@ +2008-03-27 Cary Coutant + + Add support for thin archives. + * ar.c (make_thin_archive): New global flag. + (map_over_members): Deal with full pathnames in thin archives. + (usage, main): Add 'T' option for building thin archives. + (replace_members): Pass thin archive flag to ar_emul_append. + * arsup.c (ar_open): Initialize new flag. + * binemul.c (ar_emul_append): Add new parameter for + flattening nested archives. + (do_ar_emul_default_append): New function. + (ar_emul_default_append): Factored out recursive code. + * binutils/binemul.h (ar_emul_default_append): Add new parameter. + (struct bin_emulation_xfer_struct): New parameter for ar_append. + * dlltool.c (gen_lib_file): Initialize thin archive flag. + * emul_aix.c (ar_emul_aix_internal): Add new flatten + parameter, currently unimplemented. + All callers changed. + * objcopy.c (copy_archive): Preserve thin archive flag. + * doc/binutils.texi: Update ar documentation. + * NEWS: Mention the new feature. + 2008-03-20 H.J. Lu * readelf.c (process_mips_specific): Declare addr_size as int. diff --git a/binutils/NEWS b/binutils/NEWS index a4d24332811..ab836decb36 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,4 +1,9 @@ -*- text -*- +* Added support for "thin" archives which contain pathnames pointing to + object files rather than the files themselves and which contain a + flattened symbol index for all objects, and archives, which have been + added to the archive. + * Added -F switch to objdump to include file offsets in the disassembly. * Added -c switch to readelf to allow string dumps of archive symbol index. diff --git a/binutils/ar.c b/binutils/ar.c index 10e88890f99..71f4d734612 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -40,9 +40,9 @@ #include #ifdef __GO32___ -#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ +#define EXT_NAME_LEN 3 /* Bufflen of addition to name if it's MS-DOS. */ #else -#define EXT_NAME_LEN 6 /* ditto for *NIX */ +#define EXT_NAME_LEN 6 /* Ditto for *NIX. */ #endif /* We need to open files in binary modes on system where that makes a @@ -51,12 +51,12 @@ #define O_BINARY 0 #endif -/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ +/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ struct ar_hdr * bfd_special_undocumented_glue (bfd * abfd, const char *filename); -/* Static declarations */ +/* Static declarations. */ static void mri_emul (void); static const char *normalize (const char *, bfd *); @@ -74,7 +74,7 @@ static int ranlib_only (const char *archname); static int ranlib_touch (const char *archname); static void usage (int); -/** Globals and flags */ +/** Globals and flags. */ static int mri_mode; @@ -134,6 +134,9 @@ static bfd_boolean ar_truncate = FALSE; program. */ static bfd_boolean full_pathname = FALSE; +/* Whether to create a "thin" archive (symbol index only -- no files). */ +static bfd_boolean make_thin_archive = FALSE; + int interactive = 0; static void @@ -176,16 +179,25 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count) match_count = 0; for (head = arch->archive_next; head; head = head->archive_next) { + const char * filename; + PROGRESS (1); - if (head->filename == NULL) + filename = head->filename; + if (filename == NULL) { /* Some archive formats don't get the filenames filled in until the elements are opened. */ struct stat buf; bfd_stat_arch_elt (head, &buf); } - if ((head->filename != NULL) && - (!FILENAME_CMP (normalize (*files, arch), head->filename))) + else if (bfd_is_thin_archive (arch)) + { + /* Thin archives store full pathnames. Need to normalize. */ + filename = normalize (filename, arch); + } + + if ((filename != NULL) && + (!FILENAME_CMP (normalize (*files, arch), filename))) { ++match_count; if (counted_name_mode @@ -200,6 +212,7 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count) function (head); } } + if (!found) /* xgettext:c-format */ fprintf (stderr, _("no entry %s in archive\n"), *files); @@ -242,10 +255,11 @@ usage (int help) fprintf (s, _(" [c] - do not warn if the library had to be created\n")); fprintf (s, _(" [s] - create an archive index (cf. ranlib)\n")); fprintf (s, _(" [S] - do not build a symbol table\n")); + fprintf (s, _(" [T] - make a thin archive\n")); fprintf (s, _(" [v] - be verbose\n")); fprintf (s, _(" [V] - display the version number\n")); fprintf (s, _(" @ - read options from \n")); - + ar_emul_usage (s); } else @@ -284,6 +298,7 @@ normalize (const char *file, bfd *abfd) { /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ char *bslash = strrchr (file, '\\'); + if (filename == NULL || (bslash != NULL && bslash > filename)) filename = bslash; if (filename == NULL && file[0] != '\0' && file[1] == ':') @@ -302,7 +317,7 @@ normalize (const char *file, bfd *abfd) char *s; /* Space leak. */ - s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1); + s = xmalloc (abfd->xvec->ar_max_namelen + 1); memcpy (s, filename, abfd->xvec->ar_max_namelen); s[abfd->xvec->ar_max_namelen] = '\0'; filename = s; @@ -376,6 +391,7 @@ main (int argc, char **argv) { /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ char *bslash = strrchr (program_name, '\\'); + if (temp == NULL || (bslash != NULL && bslash > temp)) temp = bslash; if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':') @@ -559,6 +575,9 @@ main (int argc, char **argv) case 'P': full_pathname = TRUE; break; + case 'T': + make_thin_archive = TRUE; + break; default: /* xgettext:c-format */ non_fatal (_("illegal option -- %c"), c); @@ -629,6 +648,9 @@ main (int argc, char **argv) arch = open_inarch (inarch_filename, files == NULL ? (char *) NULL : files[0]); + if (operation == extract && bfd_is_thin_archive (arch)) + fatal (_("`x' cannot be used on thin archives.")); + switch (operation) { case print_table: @@ -933,7 +955,7 @@ write_archive (bfd *iarch) if (new_name == NULL) bfd_fatal ("could not create temporary file whilst writing archive"); - + output_filename = new_name; obfd = bfd_openw (new_name, bfd_get_target (iarch)); @@ -956,6 +978,9 @@ write_archive (bfd *iarch) obfd->flags |= BFD_TRADITIONAL_FORMAT; } + if (make_thin_archive || bfd_is_thin_archive (iarch)) + bfd_is_thin_archive (obfd) = 1; + if (!bfd_set_archive_head (obfd, contents_head)) bfd_fatal (old_name); @@ -1189,7 +1214,8 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick) /* Add to the end of the archive. */ after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); - if (ar_emul_append (after_bfd, *files_to_move, verbose)) + if (ar_emul_append (after_bfd, *files_to_move, verbose, + make_thin_archive)) changed = TRUE; next_file:; diff --git a/binutils/arsup.c b/binutils/arsup.c index 49961b0ef11..f7138eb88ed 100644 --- a/binutils/arsup.c +++ b/binutils/arsup.c @@ -1,6 +1,6 @@ /* arsup.c - Archive support for MRI compatibility Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, - 2004, 2007 Free Software Foundation, Inc. + 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -207,6 +207,7 @@ ar_open (char *name, int t) bfd_set_format (obfd, bfd_archive); obfd->has_armap = 1; + obfd->is_thin_archive = 0; } } diff --git a/binutils/binemul.c b/binutils/binemul.c index 0eb1c816c1a..74e5d9c3849 100644 --- a/binutils/binemul.c +++ b/binutils/binemul.c @@ -1,5 +1,5 @@ /* Binutils emulation layer. - Copyright 2002, 2003, 2007 Free Software Foundation, Inc. + Copyright 2002, 2003, 2007, 2008 Free Software Foundation, Inc. Written by Tom Rix, Red Hat Inc. This file is part of GNU Binutils. @@ -39,29 +39,58 @@ ar_emul_default_usage (FILE *fp) } bfd_boolean -ar_emul_append (bfd **after_bfd, char *file_name, bfd_boolean verbose) +ar_emul_append (bfd **after_bfd, char *file_name, bfd_boolean verbose, + bfd_boolean flatten) { if (bin_dummy_emulation.ar_append) - return bin_dummy_emulation.ar_append (after_bfd, file_name, verbose); + return bin_dummy_emulation.ar_append (after_bfd, file_name, verbose, + flatten); return FALSE; } +static bfd_boolean +do_ar_emul_default_append (bfd **after_bfd, bfd *new_bfd, + bfd_boolean verbose, bfd_boolean flatten) + { + /* When flattening, add the members of an archive instead of the + archive itself. */ + if (flatten && bfd_check_format (new_bfd, bfd_archive)) + { + bfd *elt; + bfd_boolean added = FALSE; + + for (elt = bfd_openr_next_archived_file (new_bfd, NULL); + elt; + elt = bfd_openr_next_archived_file (new_bfd, elt)) + { + if (do_ar_emul_default_append (after_bfd, elt, verbose, TRUE)) + { + added = TRUE; + after_bfd = &((*after_bfd)->archive_next); + } + } + + return added; + } + + AR_EMUL_APPEND_PRINT_VERBOSE (verbose, new_bfd->filename); + + new_bfd->archive_next = *after_bfd; + *after_bfd = new_bfd; + + return TRUE; +} + bfd_boolean ar_emul_default_append (bfd **after_bfd, char *file_name, - bfd_boolean verbose) + bfd_boolean verbose, bfd_boolean flatten) { - bfd *temp; + bfd *new_bfd; - temp = *after_bfd; - *after_bfd = bfd_openr (file_name, NULL); - - AR_EMUL_ELEMENT_CHECK (*after_bfd, file_name); - AR_EMUL_APPEND_PRINT_VERBOSE (verbose, file_name); - - (*after_bfd)->archive_next = temp; - - return TRUE; + new_bfd = bfd_openr (file_name, NULL); + AR_EMUL_ELEMENT_CHECK (new_bfd, file_name); + return do_ar_emul_default_append (after_bfd, new_bfd, verbose, flatten); } bfd_boolean diff --git a/binutils/binemul.h b/binutils/binemul.h index 4da6693267e..e2a1280f9e4 100644 --- a/binutils/binemul.h +++ b/binutils/binemul.h @@ -1,5 +1,5 @@ /* Binutils emulation layer. - Copyright 2002, 2003, 2007 Free Software Foundation, Inc. + Copyright 2002, 2003, 2007, 2008 Free Software Foundation, Inc. Written by Tom Rix, Red Hat Inc. This file is part of GNU Binutils. @@ -28,8 +28,9 @@ extern void ar_emul_usage (FILE *); extern void ar_emul_default_usage (FILE *); -extern bfd_boolean ar_emul_append (bfd **, char *, bfd_boolean); -extern bfd_boolean ar_emul_default_append (bfd **, char *, bfd_boolean); +extern bfd_boolean ar_emul_append (bfd **, char *, bfd_boolean, bfd_boolean); +extern bfd_boolean ar_emul_default_append (bfd **, char *, bfd_boolean, + bfd_boolean); extern bfd_boolean ar_emul_replace (bfd **, char *, bfd_boolean); extern bfd_boolean ar_emul_default_replace (bfd **, char *, bfd_boolean); extern bfd_boolean ar_emul_parse_arg (char *); @@ -54,7 +55,7 @@ typedef struct bin_emulation_xfer_struct { /* Print out the extra options. */ void (* ar_usage) (FILE *fp); - bfd_boolean (* ar_append) (bfd **, char *, bfd_boolean); + bfd_boolean (* ar_append) (bfd **, char *, bfd_boolean, bfd_boolean); bfd_boolean (* ar_replace) (bfd **, char *, bfd_boolean); bfd_boolean (* ar_parse_arg) (char *); } diff --git a/binutils/dlltool.c b/binutils/dlltool.c index cbdde7c6d42..61361b74a3d 100644 --- a/binutils/dlltool.c +++ b/binutils/dlltool.c @@ -2813,6 +2813,7 @@ gen_lib_file (void) bfd_set_format (outarch, bfd_archive); outarch->has_armap = 1; + outarch->is_thin_archive = 0; /* Work out a reasonable size of things to put onto one line. */ ar_head = make_head (); diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 723c3a38b2d..44c18dc3434 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -211,6 +211,18 @@ You may use @samp{nm -s} or @samp{nm --print-armap} to list this index table. If an archive lacks the table, another form of @command{ar} called @command{ranlib} can be used to add just the table. +@cindex thin archives +@sc{gnu} @command{ar} can optionally create a @emph{thin} archive, +which contains a symbol index and references to the original copies +of the member files of the archives. Such an archive is useful +for building libraries for use within a local build, where the +relocatable objects are expected to remain available, and copying the +contents of each object would only waste time and space. Thin archives +are also @emph{flattened}, so that adding one or more archives to a +thin archive will add the elements of the nested archive individually. +The paths to the elements of the archive are stored relative to the +archive itself. + @cindex compatibility, @command{ar} @cindex @command{ar} compatibility @sc{gnu} @command{ar} is designed to be compatible with two different @@ -356,6 +368,8 @@ use the @samp{v} modifier with this operation, to request that If you do not specify a @var{member}, all files in the archive are extracted. +Files cannot be extracted from a thin archive. + @end table A number of modifiers (@var{mod}) may immediately follow the @var{p} @@ -434,6 +448,12 @@ with the linker. In order to build a symbol table, you must omit the @samp{S} modifier on the last execution of @samp{ar}, or you must run @samp{ranlib} on the archive. +@item T +@cindex creating thin archive +Make the specified @var{archive} a @emph{thin} archive. If it already +exists and is a regular archive, the existing members must be present +in the same directory as @var{archive}. + @item u @cindex updating an archive Normally, @samp{ar r}@dots{} inserts all files diff --git a/binutils/emul_aix.c b/binutils/emul_aix.c index 22ff8300479..d68a5ec0b50 100644 --- a/binutils/emul_aix.c +++ b/binutils/emul_aix.c @@ -1,5 +1,5 @@ /* Binutils emulation layer. - Copyright 2002, 2003, 2006, 2007 Free Software Foundation, Inc. + Copyright 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc. Written by Tom Rix, Red Hat Inc. This file is part of GNU Binutils. @@ -35,15 +35,6 @@ static bfd_boolean X32 = TRUE; /* Whether to include 64 bit objects. */ static bfd_boolean X64 = FALSE; -static void ar_emul_aix_usage (FILE *); -static bfd_boolean ar_emul_aix_append (bfd **, char *, bfd_boolean); -static bfd_boolean ar_emul_aix5_append (bfd **, char *, bfd_boolean); -static bfd_boolean ar_emul_aix_replace (bfd **, char *, bfd_boolean); -static bfd_boolean ar_emul_aix5_replace (bfd **, char *, bfd_boolean); -static bfd_boolean ar_emul_aix_parse_arg (char *); -static bfd_boolean ar_emul_aix_internal - (bfd **, char *, bfd_boolean, const char *, bfd_boolean); - static void ar_emul_aix_usage (FILE *fp) { @@ -56,8 +47,12 @@ ar_emul_aix_usage (FILE *fp) } static bfd_boolean -ar_emul_aix_internal (bfd **after_bfd, char *file_name, bfd_boolean verbose, - const char * target_name, bfd_boolean is_append) +ar_emul_aix_internal (bfd ** after_bfd, + char * file_name, + bfd_boolean verbose, + const char * target_name, + bfd_boolean is_append, + bfd_boolean flatten ATTRIBUTE_UNUSED) { bfd *temp; bfd *try_bfd; @@ -97,31 +92,33 @@ ar_emul_aix_internal (bfd **after_bfd, char *file_name, bfd_boolean verbose, static bfd_boolean -ar_emul_aix_append (bfd **after_bfd, char *file_name, bfd_boolean verbose) +ar_emul_aix_append (bfd **after_bfd, char *file_name, bfd_boolean verbose, + bfd_boolean flatten) { return ar_emul_aix_internal (after_bfd, file_name, verbose, - "aixcoff64-rs6000", TRUE); + "aixcoff64-rs6000", TRUE, flatten); } static bfd_boolean -ar_emul_aix5_append (bfd **after_bfd, char *file_name, bfd_boolean verbose) +ar_emul_aix5_append (bfd **after_bfd, char *file_name, bfd_boolean verbose, + bfd_boolean flatten) { return ar_emul_aix_internal (after_bfd, file_name, verbose, - "aix5coff64-rs6000", TRUE); + "aix5coff64-rs6000", TRUE, flatten); } static bfd_boolean ar_emul_aix_replace (bfd **after_bfd, char *file_name, bfd_boolean verbose) { return ar_emul_aix_internal (after_bfd, file_name, verbose, - "aixcoff64-rs6000", FALSE); + "aixcoff64-rs6000", FALSE, FALSE); } static bfd_boolean ar_emul_aix5_replace (bfd **after_bfd, char *file_name, bfd_boolean verbose) { return ar_emul_aix_internal (after_bfd, file_name, verbose, - "aix5coff64-rs6000", FALSE); + "aix5coff64-rs6000", FALSE, FALSE); } static bfd_boolean diff --git a/binutils/objcopy.c b/binutils/objcopy.c index b89de465619..1dd36114e90 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -1,6 +1,6 @@ /* objcopy.c -- copy object file from input to output, optionally massaging it. Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -1830,6 +1830,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target, strerror (errno)); obfd->has_armap = ibfd->has_armap; + obfd->is_thin_archive = ibfd->is_thin_archive; list = NULL; diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index ac5be6d0c64..e7cc69ace14 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-03-27 Cary Coutant + + * binutils-all/ar.exp: Add thin archive tests. + 2008-02-26 Joseph Myers * config/default.exp (gcc_gas_flag, dlltool_gas_flag): Define to diff --git a/binutils/testsuite/binutils-all/ar.exp b/binutils/testsuite/binutils-all/ar.exp index 67504c3f72a..21a39f48ea6 100644 --- a/binutils/testsuite/binutils-all/ar.exp +++ b/binutils/testsuite/binutils-all/ar.exp @@ -1,4 +1,4 @@ -# Copyright 1995, 1997, 2002, 2004, 2007 Free Software Foundation, Inc. +# Copyright 1995, 1997, 2002, 2004, 2007, 2008 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -215,6 +215,110 @@ proc symbol_table { } { pass $testname } +# Test building a thin archive. + +proc thin_archive { } { + global AR + global AS + global NM + global srcdir + global subdir + + set testname "ar thin archive" + + if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o] { + unresolved $testname + return + } + + if [is_remote host] { + set archive artest.a + set objfile [remote_download host tmpdir/bintest.o] + remote_file host delete $archive + } else { + set archive tmpdir/artest.a + set objfile tmpdir/bintest.o + } + + remote_file build delete tmpdir/artest.a + + set got [binutils_run $AR "rcT $archive ${objfile}"] + if ![string match "" $got] { + fail $testname + return + } + + set got [binutils_run $NM "--print-armap $archive"] + if { ![string match "*text_symbol in *bintest.o*" $got] \ + || ![string match "*data_symbol in *bintest.o*" $got] \ + || ![string match "*common_symbol in *bintest.o*" $got] \ + || [string match "*static_text_symbol in *bintest.o*" $got] \ + || [string match "*static_data_symbol in *bintest.o*" $got] \ + || [string match "*external_symbol in *bintest.o*" $got] } { + fail $testname + return + } + + pass $testname +} + +# Test building a thin archive with a nested archive. + +proc thin_archive_with_nested { } { + global AR + global AS + global NM + global srcdir + global subdir + + set testname "ar thin archive with nested archive" + + if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o] { + unresolved $testname + return + } + + if [is_remote host] { + set archive artest.a + set archive2 artest2.a + set objfile [remote_download host tmpdir/bintest.o] + remote_file host delete $archive + } else { + set archive tmpdir/artest.a + set archive2 tmpdir/artest2.a + set objfile tmpdir/bintest.o + } + + remote_file build delete tmpdir/artest.a + + set got [binutils_run $AR "rc $archive ${objfile}"] + if ![string match "" $got] { + fail $testname + return + } + + remote_file build delete tmpdir/artest2.a + + set got [binutils_run $AR "rcT $archive2 ${archive}"] + if ![string match "" $got] { + fail $testname + return + } + + set got [binutils_run $NM "--print-armap $archive"] + if { ![string match "*text_symbol in *bintest.o*" $got] \ + || ![string match "*data_symbol in *bintest.o*" $got] \ + || ![string match "*common_symbol in *bintest.o*" $got] \ + || [string match "*static_text_symbol in *bintest.o*" $got] \ + || [string match "*static_data_symbol in *bintest.o*" $got] \ + || [string match "*external_symbol in *bintest.o*" $got] } { + fail $testname + return + } + + pass $testname +} + # Test POSIX-compatible argument parsing. proc argument_parsing { } { @@ -254,4 +358,6 @@ proc argument_parsing { } { long_filenames symbol_table +thin_archive +thin_archive_with_nested argument_parsing diff --git a/include/aout/ChangeLog b/include/aout/ChangeLog index e00c698c3cc..6d1f374e2c9 100644 --- a/include/aout/ChangeLog +++ b/include/aout/ChangeLog @@ -1,3 +1,7 @@ +2008-03-27 Cary Coutant + + * ar.h (ARMAGT): New magic string for thin archives. + 2005-05-10 Nick Clifton * Update the address and phone number of the FSF organization in diff --git a/include/aout/ar.h b/include/aout/ar.h index 0d0aad2d5e3..7b77997915b 100644 --- a/include/aout/ar.h +++ b/include/aout/ar.h @@ -1,6 +1,6 @@ /* archive file definition for GNU software - Copyright 2001 Free Software Foundation, Inc. + Copyright 2001, 2008 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,8 +26,9 @@ characters, as allowed by ANSI. '\012' has a fixed value, and remains compatible with existing BSDish archives. */ -#define ARMAG "!\012" /* For COFF and a.out archives */ -#define ARMAGB "!\012" /* For b.out archives */ +#define ARMAG "!\012" /* For COFF and a.out archives. */ +#define ARMAGB "!\012" /* For b.out archives. */ +#define ARMAGT "!\012" /* For thin archives. */ #define SARMAG 8 #define ARFMAG "`\012" @@ -39,14 +40,15 @@ #define ARMAP_TIME_OFFSET 60 -struct ar_hdr { - char ar_name[16]; /* name of this member */ - char ar_date[12]; /* file mtime */ - char ar_uid[6]; /* owner uid; printed as decimal */ - char ar_gid[6]; /* owner gid; printed as decimal */ - char ar_mode[8]; /* file mode, printed as octal */ - char ar_size[10]; /* file size, printed as decimal */ - char ar_fmag[2]; /* should contain ARFMAG */ +struct ar_hdr +{ + char ar_name[16]; /* Name of this member. */ + char ar_date[12]; /* File mtime. */ + char ar_uid[6]; /* Owner uid; printed as decimal. */ + char ar_gid[6]; /* Owner gid; printed as decimal. */ + char ar_mode[8]; /* File mode, printed as octal. */ + char ar_size[10]; /* File size, printed as decimal. */ + char ar_fmag[2]; /* Should contain ARFMAG. */ }; #endif /* __GNU_AR_H__ */