From 5ea1af0d5d96234b6c086f284c2fc66ad58b279b Mon Sep 17 00:00:00 2001 From: Geoffrey Keating Date: Sat, 19 Feb 2000 00:59:26 +0000 Subject: [PATCH] * coffcode.h (coff_set_arch_mach_hook): Don't use variable-size arrays. (coff_compute_section_file_positions): Use bfd_free to pair bfd_malloc. (coff_write_object_contents): Likewise. * coff-rs6000.c (xcoff_howto_table_16): New variable. (xcoff_rtype2howto): Handle 16-bit variants of 32-bit relocs. --- bfd/ChangeLog | 11 + bfd/coff-rs6000.c | 856 ++++++++++++++++++++++++++++++++++++++++++---- bfd/coffcode.h | 18 +- 3 files changed, 804 insertions(+), 81 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index fd6bd809d1..1d27603462 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +2000-02-18 Geoff Keating + + * coffcode.h (coff_set_arch_mach_hook): Don't use variable-size + arrays. + (coff_compute_section_file_positions): Use bfd_free to pair + bfd_malloc. + (coff_write_object_contents): Likewise. + + * coff-rs6000.c (xcoff_howto_table_16): New variable. + (xcoff_rtype2howto): Handle 16-bit variants of 32-bit relocs. + 2000-02-18 Richard Henderson * elf-bfd.h (struct elf_link_hash_table): Remove copy_indirect diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 69230001e4..6f8563f911 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -496,6 +496,55 @@ static reloc_howto_type xcoff_howto_table[] = false) /* pcrel_offset */ }; +/* These are the first two like the above but for 16-bit relocs. */ +static reloc_howto_type xcoff_howto_table_16[] = +{ + /* Standard 16 bit relocation. */ + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_POS_16", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit relocation, but store negative value. */ + HOWTO (1, /* type */ + 0, /* rightshift */ + -2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_NEG_16", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit PC relative relocation. */ + HOWTO (2, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL_16", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ +}; + static void xcoff_rtype2howto (relent, internal) arelent *relent; @@ -503,6 +552,11 @@ xcoff_rtype2howto (relent, internal) { relent->howto = xcoff_howto_table + internal->r_type; + if (relent->howto->bitsize != ((unsigned int) internal->r_size & 0x1f) + 1 + && (internal->r_type + < sizeof(xcoff_howto_table_16)/sizeof(xcoff_howto_table_16[0]))) + relent->howto = xcoff_howto_table_16 + internal->r_type; + /* The r_size field of an XCOFF reloc encodes the bitsize of the relocation, as well as indicating whether it is signed or not. Doublecheck that the relocation information gathered from the @@ -591,12 +645,25 @@ xcoff_reloc_type_lookup (abfd, code) binary number which is the number of entries. This is followed by a that many four byte binary numbers; each is the file offset of an entry in the archive. These numbers are followed by a series of - null terminated strings, which are symbol names. */ + null terminated strings, which are symbol names. -/* XCOFF archives use this as a magic string. */ + AIX 4.3 introduced a new archive format which can handle larger + files and also 32- and 64-bit objects in the same archive. The + things said above remain true except that there is now more than + one global symbol table. The one is used to index 32-bit objects, + the other for 64-bit objects. -#define XCOFFARMAG "\012" -#define SXCOFFARMAG 8 + The new archives (recognizable by the new ARMAG string) has larger + field lengths so that we cannot really share any code. Also we have + to take care that we are not generating the new form of archives + on AIX 4.2 or earlier systems. */ + +/* XCOFF archives use this as a magic string. Note that both strings + have the same length. */ + +#define XCOFFARMAG "\012" +#define XCOFFARMAGBIG "\012" +#define SXCOFFARMAG 8 /* This terminates an XCOFF archive member name. */ @@ -629,6 +696,38 @@ struct xcoff_ar_file_hdr #define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG) +/* This is the equivalent data structure for the big archive format. */ + +struct xcoff_ar_file_hdr_big +{ + /* Magic string. */ + char magic[SXCOFFARMAG]; + + /* Offset of the member table (decimal ASCII string). */ + char memoff[20]; + + /* Offset of the global symbol table for 32-bit objects (decimal ASCII + string). */ + char symoff[20]; + + /* Offset of the global symbol table for 64-bit objects (decimal ASCII + string). */ + char symoff64[20]; + + /* Offset of the first member in the archive (decimal ASCII string). */ + char firstmemoff[20]; + + /* Offset of the last member in the archive (decimal ASCII string). */ + char lastmemoff[20]; + + /* Offset of the first member on the free list (decimal ASCII + string). */ + char freeoff[20]; +}; + +#define SIZEOF_AR_FILE_HDR_BIG (6 * 20 + SXCOFFARMAG) + + /* Each XCOFF archive member starts with this (printable) structure. */ struct xcoff_ar_hdr @@ -667,16 +766,65 @@ struct xcoff_ar_hdr #define SIZEOF_AR_HDR (7 * 12 + 4) +/* The equivalent for the big archive format. */ + +struct xcoff_ar_hdr_big +{ + /* File size not including the header (decimal ASCII string). */ + char size[20]; + + /* File offset of next archive member (decimal ASCII string). */ + char nextoff[20]; + + /* File offset of previous archive member (decimal ASCII string). */ + char prevoff[20]; + + /* File mtime (decimal ASCII string). */ + char date[12]; + + /* File UID (decimal ASCII string). */ + char uid[12]; + + /* File GID (decimal ASCII string). */ + char gid[12]; + + /* File mode (octal ASCII string). */ + char mode[12]; + + /* Length of file name (decimal ASCII string). */ + char namlen[4]; + + /* This structure is followed by the file name. The length of the + name is given in the namlen field. If the length of the name is + odd, the name is followed by a null byte. The name and optional + null byte are followed by XCOFFARFMAG, which is not included in + namlen. The contents of the archive member follow; the number of + bytes is given in the size field. */ +}; + +#define SIZEOF_AR_HDR_BIG (3 * 20 + 4 * 12 + 4) + + +/* We often have to distinguish between the old and big file format. + Make it a bit cleaner. We can use `xcoff_ardata' here because the + `hdr' member has the same size and position in both formats. */ +#define xcoff_big_format_p(abfd) \ + (xcoff_ardata (abfd)->magic[1] == 'b') + /* We store a copy of the xcoff_ar_file_hdr in the tdata field of the - artdata structure. */ + artdata structure. Similar for the big archive. */ #define xcoff_ardata(abfd) \ ((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata) +#define xcoff_ardata_big(abfd) \ + ((struct xcoff_ar_file_hdr_big *) bfd_ardata (abfd)->tdata) /* We store a copy of the xcoff_ar_hdr in the arelt_data field of an - archive element. */ + archive element. Similar for the big archive. */ #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) #define arch_xhdr(bfd) \ ((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header) +#define arch_xhdr_big(bfd) \ + ((struct xcoff_ar_hdr_big *) arch_eltdata (bfd)->arch_header) /* XCOFF archives do not have anything which corresponds to an extended name table. */ @@ -702,7 +850,6 @@ xcoff_slurp_armap (abfd) bfd *abfd; { file_ptr off; - struct xcoff_ar_hdr hdr; size_t namlen; bfd_size_type sz; bfd_byte *contents, *cend; @@ -716,27 +863,64 @@ xcoff_slurp_armap (abfd) return true; } - off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10); - if (off == 0) + if (! xcoff_big_format_p (abfd)) { - bfd_has_map (abfd) = false; - return true; + /* This is for the old format. */ + struct xcoff_ar_hdr hdr; + + off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10); + if (off == 0) + { + bfd_has_map (abfd) = false; + return true; + } + + if (bfd_seek (abfd, off, SEEK_SET) != 0) + return false; + + /* The symbol table starts with a normal archive header. */ + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) + return false; + + /* Skip the name (normally empty). */ + namlen = strtol (hdr.namlen, (char **) NULL, 10); + if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return false; + + sz = strtol (hdr.size, (char **) NULL, 10); + } + else + { + /* This is for the new format. */ + struct xcoff_ar_hdr_big hdr; + + off = strtol (xcoff_ardata_big (abfd)->symoff, (char **) NULL, 10); + if (off == 0) + { + bfd_has_map (abfd) = false; + return true; + } + + if (bfd_seek (abfd, off, SEEK_SET) != 0) + return false; + + /* The symbol table starts with a normal archive header. */ + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd) + != SIZEOF_AR_HDR_BIG) + return false; + + /* Skip the name (normally empty). */ + namlen = strtol (hdr.namlen, (char **) NULL, 10); + if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return false; + + /* XXX This actually has to be a call to strtoll (at least on 32-bit + machines) since the field width is 20 and there numbers with more + than 32 bits can be represented. */ + sz = strtol (hdr.size, (char **) NULL, 10); } - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return false; - - /* The symbol table starts with a normal archive header. */ - if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) - return false; - - /* Skip the name (normally empty). */ - namlen = strtol (hdr.namlen, (char **) NULL, 10); - if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0) - return false; - /* Read in the entire symbol table. */ - sz = strtol (hdr.size, (char **) NULL, 10); contents = (bfd_byte *) bfd_alloc (abfd, sz); if (contents == NULL) return false; @@ -789,17 +973,17 @@ static const bfd_target * xcoff_archive_p (abfd) bfd *abfd; { - struct xcoff_ar_file_hdr hdr; + char magic[SXCOFFARMAG]; - if (bfd_read ((PTR) &hdr, SIZEOF_AR_FILE_HDR, 1, abfd) - != SIZEOF_AR_FILE_HDR) + if (bfd_read ((PTR) magic, SXCOFFARMAG, 1, abfd) != SXCOFFARMAG) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_wrong_format); return NULL; } - if (strncmp (hdr.magic, XCOFFARMAG, SXCOFFARMAG) != 0) + if (strncmp (magic, XCOFFARMAG, SXCOFFARMAG) != 0 + && strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0) { bfd_set_error (bfd_error_wrong_format); return NULL; @@ -814,18 +998,67 @@ xcoff_archive_p (abfd) if (bfd_ardata (abfd) == (struct artdata *) NULL) return NULL; - bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff, - (char **) NULL, 10); bfd_ardata (abfd)->cache = NULL; bfd_ardata (abfd)->archive_head = NULL; bfd_ardata (abfd)->symdefs = NULL; bfd_ardata (abfd)->extended_names = NULL; - bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR); - if (bfd_ardata (abfd)->tdata == NULL) - return NULL; + /* Now handle the two formats. */ + if (magic[1] != 'b') + { + /* This is the old format. */ + struct xcoff_ar_file_hdr hdr; - memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR); + /* Copy over the magic string. */ + memcpy (hdr.magic, magic, SXCOFFARMAG); + + /* Now read the rest of the file header. */ + if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR - SXCOFFARMAG, 1, + abfd) != SIZEOF_AR_FILE_HDR - SXCOFFARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff, + (char **) NULL, 10); + + bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR); + if (bfd_ardata (abfd)->tdata == NULL) + return NULL; + + memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR); + } + else + { + /* This is the new format. */ + struct xcoff_ar_file_hdr_big hdr; + + /* Copy over the magic string. */ + memcpy (hdr.magic, magic, SXCOFFARMAG); + + /* Now read the rest of the file header. */ + if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG, 1, + abfd) != SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* XXX This actually has to be a call to strtoll (at least on 32-bit + machines) since the field width is 20 and there numbers with more + than 32 bits can be represented. */ + bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff, + (char **) NULL, 10); + + bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR_BIG); + if (bfd_ardata (abfd)->tdata == NULL) + return NULL; + + memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG); + } if (! xcoff_slurp_armap (abfd)) { @@ -843,29 +1076,80 @@ static PTR xcoff_read_ar_hdr (abfd) bfd *abfd; { - struct xcoff_ar_hdr hdr; size_t namlen; - struct xcoff_ar_hdr *hdrp; struct areltdata *ret; - if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) - return NULL; - - namlen = strtol (hdr.namlen, (char **) NULL, 10); - hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1); - if (hdrp == NULL) - return NULL; - memcpy (hdrp, &hdr, SIZEOF_AR_HDR); - if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen) - return NULL; - ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0'; - ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata)); if (ret == NULL) return NULL; - ret->arch_header = (char *) hdrp; - ret->parsed_size = strtol (hdr.size, (char **) NULL, 10); - ret->filename = (char *) hdrp + SIZEOF_AR_HDR; + + if (! xcoff_big_format_p (abfd)) + { + struct xcoff_ar_hdr hdr; + struct xcoff_ar_hdr *hdrp; + + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) + { + free (ret); + return NULL; + } + + namlen = strtol (hdr.namlen, (char **) NULL, 10); + hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, + SIZEOF_AR_HDR + namlen + 1); + if (hdrp == NULL) + { + free (ret); + return NULL; + } + memcpy (hdrp, &hdr, SIZEOF_AR_HDR); + if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen) + { + free (ret); + return NULL; + } + ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0'; + + ret->arch_header = (char *) hdrp; + ret->parsed_size = strtol (hdr.size, (char **) NULL, 10); + ret->filename = (char *) hdrp + SIZEOF_AR_HDR; + } + else + { + struct xcoff_ar_hdr_big hdr; + struct xcoff_ar_hdr_big *hdrp; + + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd) + != SIZEOF_AR_HDR_BIG) + { + free (ret); + return NULL; + } + + namlen = strtol (hdr.namlen, (char **) NULL, 10); + hdrp = (struct xcoff_ar_hdr_big *) bfd_alloc (abfd, + SIZEOF_AR_HDR_BIG + + namlen + 1); + if (hdrp == NULL) + { + free (ret); + return NULL; + } + memcpy (hdrp, &hdr, SIZEOF_AR_HDR_BIG); + if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR_BIG, 1, namlen, abfd) != namlen) + { + free (ret); + return NULL; + } + ((char *) hdrp)[SIZEOF_AR_HDR_BIG + namlen] = '\0'; + + ret->arch_header = (char *) hdrp; + /* XXX This actually has to be a call to strtoll (at least on 32-bit + machines) since the field width is 20 and there numbers with more + than 32 bits can be represented. */ + ret->parsed_size = strtol (hdr.size, (char **) NULL, 10); + ret->filename = (char *) hdrp + SIZEOF_AR_HDR_BIG; + } /* Skip over the XCOFFARFMAG at the end of the file name. */ if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0) @@ -889,19 +1173,47 @@ xcoff_openr_next_archived_file (archive, last_file) return NULL; } - if (last_file == NULL) - filestart = bfd_ardata (archive)->first_file_filepos; - else - filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, 10); - - if (filestart == 0 - || filestart == strtol (xcoff_ardata (archive)->memoff, - (char **) NULL, 10) - || filestart == strtol (xcoff_ardata (archive)->symoff, - (char **) NULL, 10)) + if (! xcoff_big_format_p (archive)) { - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, + 10); + + if (filestart == 0 + || filestart == strtol (xcoff_ardata (archive)->memoff, + (char **) NULL, 10) + || filestart == strtol (xcoff_ardata (archive)->symoff, + (char **) NULL, 10)) + { + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + } + else + { + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + /* XXX These actually have to be a calls to strtoll (at least + on 32-bit machines) since the fields's width is 20 and + there numbers with more than 32 bits can be represented. */ + filestart = strtol (arch_xhdr_big (last_file)->nextoff, (char **) NULL, + 10); + + /* XXX These actually have to be calls to strtoll (at least on 32-bit + machines) since the fields's width is 20 and there numbers with more + than 32 bits can be represented. */ + if (filestart == 0 + || filestart == strtol (xcoff_ardata_big (archive)->memoff, + (char **) NULL, 10) + || filestart == strtol (xcoff_ardata_big (archive)->symoff, + (char **) NULL, 10)) + { + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } } return _bfd_get_elt_at_filepos (archive, filestart); @@ -914,21 +1226,32 @@ xcoff_generic_stat_arch_elt (abfd, s) bfd *abfd; struct stat *s; { - struct xcoff_ar_hdr *hdrp; - if (abfd->arelt_data == NULL) { bfd_set_error (bfd_error_invalid_operation); return -1; } - hdrp = arch_xhdr (abfd); + if (! xcoff_big_format_p (abfd)) + { + struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd); - s->st_mtime = strtol (hdrp->date, (char **) NULL, 10); - s->st_uid = strtol (hdrp->uid, (char **) NULL, 10); - s->st_gid = strtol (hdrp->gid, (char **) NULL, 10); - s->st_mode = strtol (hdrp->mode, (char **) NULL, 8); - s->st_size = arch_eltdata (abfd)->parsed_size; + s->st_mtime = strtol (hdrp->date, (char **) NULL, 10); + s->st_uid = strtol (hdrp->uid, (char **) NULL, 10); + s->st_gid = strtol (hdrp->gid, (char **) NULL, 10); + s->st_mode = strtol (hdrp->mode, (char **) NULL, 8); + s->st_size = arch_eltdata (abfd)->parsed_size; + } + else + { + struct xcoff_ar_hdr_big *hdrp = arch_xhdr_big (abfd); + + s->st_mtime = strtol (hdrp->date, (char **) NULL, 10); + s->st_uid = strtol (hdrp->uid, (char **) NULL, 10); + s->st_gid = strtol (hdrp->gid, (char **) NULL, 10); + s->st_mode = strtol (hdrp->mode, (char **) NULL, 8); + s->st_size = arch_eltdata (abfd)->parsed_size; + } return 0; } @@ -955,7 +1278,7 @@ normalize_filename (abfd) /*ARGSUSED*/ static boolean -xcoff_write_armap (abfd, elength, map, orl_count, stridx) +xcoff_write_armap_old (abfd, elength, map, orl_count, stridx) bfd *abfd; unsigned int elength ATTRIBUTE_UNUSED; struct orl *map; @@ -987,7 +1310,7 @@ xcoff_write_armap (abfd, elength, map, orl_count, stridx) if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG) return false; - + bfd_h_put_32 (abfd, orl_count, buf); if (bfd_write (buf, 1, 4, abfd) != 4) return false; @@ -1039,11 +1362,115 @@ xcoff_write_armap (abfd, elength, map, orl_count, stridx) return true; } +/*ARGSUSED*/ +static boolean +xcoff_write_armap_big (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength ATTRIBUTE_UNUSED; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + struct xcoff_ar_hdr_big hdr; + char *p; + unsigned char buf[4]; + bfd *sub; + file_ptr fileoff; + unsigned int i; + + memset (&hdr, 0, sizeof hdr); + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx)); + sprintf (hdr.nextoff, "%d", 0); + memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12); + sprintf (hdr.date, "%d", 0); + sprintf (hdr.uid, "%d", 0); + sprintf (hdr.gid, "%d", 0); + sprintf (hdr.mode, "%d", 0); + sprintf (hdr.namlen, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR_BIG; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd) != SIZEOF_AR_HDR_BIG + || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG) + return false; + + bfd_h_put_32 (abfd, orl_count, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + + sub = abfd->archive_head; + fileoff = SIZEOF_AR_FILE_HDR_BIG; + i = 0; + while (sub != NULL && i < orl_count) + { + size_t namlen; + + while (((bfd *) (map[i]).pos) == sub) + { + bfd_h_put_32 (abfd, fileoff, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + ++i; + } + namlen = strlen (normalize_filename (sub)); + namlen = (namlen + 1) &~ 1; + fileoff += (SIZEOF_AR_HDR_BIG + + namlen + + SXCOFFARFMAG + + arelt_size (sub)); + fileoff = (fileoff + 1) &~ 1; + sub = sub->next; + } + + for (i = 0; i < orl_count; i++) + { + const char *name; + size_t namlen; + + name = *map[i].name; + namlen = strlen (name); + if (bfd_write (name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + + if ((stridx & 1) != 0) + { + char b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/*ARGSUSED*/ +static boolean +xcoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength ATTRIBUTE_UNUSED; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + if (! xcoff_big_format_p (abfd)) + return xcoff_write_armap_old (abfd, elength, map, orl_count, stridx); + else + return xcoff_write_armap_big (abfd, elength, map, orl_count, stridx); +} + /* Write out an XCOFF archive. We always write an entire archive, rather than fussing with the freelist and so forth. */ static boolean -xcoff_write_archive_contents (abfd) +xcoff_write_archive_contents_old (abfd) bfd *abfd; { struct xcoff_ar_file_hdr fhdr; @@ -1286,6 +1713,285 @@ xcoff_write_archive_contents (abfd) return true; } + +static boolean +xcoff_write_archive_contents_big (abfd) + bfd *abfd; +{ + struct xcoff_ar_file_hdr_big fhdr; + size_t count; + size_t total_namlen; + file_ptr *offsets; + boolean makemap; + boolean hasobjects; + file_ptr prevoff, nextoff; + bfd *sub; + unsigned int i; + struct xcoff_ar_hdr_big ahdr; + bfd_size_type size; + char *p; + char decbuf[13]; + + memset (&fhdr, 0, sizeof fhdr); + strncpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG); + sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR_BIG); + sprintf (fhdr.freeoff, "%d", 0); + + count = 0; + total_namlen = 0; + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + ++count; + total_namlen += strlen (normalize_filename (sub)) + 1; + } + offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr)); + if (offsets == NULL) + return false; + + if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0) + return false; + + makemap = bfd_has_map (abfd); + hasobjects = false; + prevoff = 0; + nextoff = SIZEOF_AR_FILE_HDR_BIG; + for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++) + { + const char *name; + size_t namlen; + struct xcoff_ar_hdr_big *ahdrp; + bfd_size_type remaining; + + if (makemap && ! hasobjects) + { + if (bfd_check_format (sub, bfd_object)) + hasobjects = true; + } + + name = normalize_filename (sub); + namlen = strlen (name); + + if (sub->arelt_data != NULL) + ahdrp = arch_xhdr_big (sub); + else + ahdrp = NULL; + + if (ahdrp == NULL) + { + struct stat s; + + memset (&ahdr, 0, sizeof ahdr); + ahdrp = &ahdr; + /* XXX This should actually be a call to stat64 (at least on + 32-bit machines). */ + if (stat (bfd_get_filename (sub), &s) != 0) + { + bfd_set_error (bfd_error_system_call); + return false; + } + + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (ahdrp->size, "%ld", (long) s.st_size); + sprintf (ahdrp->date, "%ld", (long) s.st_mtime); + sprintf (ahdrp->uid, "%ld", (long) s.st_uid); + sprintf (ahdrp->gid, "%ld", (long) s.st_gid); + sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode); + + if (sub->arelt_data == NULL) + { + sub->arelt_data = bfd_alloc (sub, sizeof (struct areltdata)); + if (sub->arelt_data == NULL) + return false; + } + + arch_eltdata (sub)->parsed_size = s.st_size; + } + + /* XXX These calls actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (ahdrp->prevoff, "%ld", (long) prevoff); + sprintf (ahdrp->namlen, "%ld", (long) namlen); + + /* If the length of the name is odd, we write out the null byte + after the name as well. */ + namlen = (namlen + 1) &~ 1; + + remaining = arelt_size (sub); + size = (SIZEOF_AR_HDR_BIG + + namlen + + SXCOFFARFMAG + + remaining); + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + + offsets[i] = nextoff; + + prevoff = nextoff; + nextoff += size + (size & 1); + + sprintf (ahdrp->nextoff, "%ld", (long) nextoff); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR_BIG; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR_BIG, abfd) + != SIZEOF_AR_HDR_BIG + || bfd_write ((PTR) name, 1, namlen, abfd) != namlen + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) + return false; + + if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0) + return false; + while (remaining != 0) + { + bfd_size_type amt; + bfd_byte buffer[DEFAULT_BUFFERSIZE]; + + amt = sizeof buffer; + if (amt > remaining) + amt = remaining; + if (bfd_read (buffer, 1, amt, sub) != amt + || bfd_write (buffer, 1, amt, abfd) != amt) + return false; + remaining -= amt; + } + + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + } + + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (fhdr.lastmemoff, "%ld", (long) prevoff); + + /* Write out the member table. */ + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (fhdr.memoff, "%ld", (long) nextoff); + + memset (&ahdr, 0, sizeof ahdr); + /* XXX The next two calls actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen)); + sprintf (ahdr.prevoff, "%ld", (long) prevoff); + sprintf (ahdr.date, "%d", 0); + sprintf (ahdr.uid, "%d", 0); + sprintf (ahdr.gid, "%d", 0); + sprintf (ahdr.mode, "%d", 0); + sprintf (ahdr.namlen, "%d", 0); + + size = (SIZEOF_AR_HDR_BIG + + 12 + + count * 12 + + total_namlen + + SXCOFFARFMAG); + + prevoff = nextoff; + nextoff += size + (size & 1); + + if (makemap && hasobjects) + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (ahdr.nextoff, "%ld", (long) nextoff); + else + sprintf (ahdr.nextoff, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR_BIG; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) + return false; + + sprintf (decbuf, "%-12ld", (long) count); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + for (i = 0; i < count; i++) + { + sprintf (decbuf, "%-12ld", (long) offsets[i]); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + } + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + const char *name; + size_t namlen; + + name = normalize_filename (sub); + namlen = strlen (name); + if (bfd_write ((PTR) name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write ((PTR) &b, 1, 1, abfd) != 1) + return false; + } + + /* Write out the armap, if appropriate. */ + + if (! makemap || ! hasobjects) + sprintf (fhdr.symoff, "%d", 0); + else + { + BFD_ASSERT (nextoff == bfd_tell (abfd)); + /* XXX This call actually should use %lld (at least on 32-bit + machines) since the fields's width is 20 and there numbers with + more than 32 bits can be represented. */ + sprintf (fhdr.symoff, "%ld", (long) nextoff); + bfd_ardata (abfd)->tdata = (PTR) &fhdr; + if (! _bfd_compute_and_write_armap (abfd, 0)) + return false; + } + + /* Write out the archive file header. */ + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR_BIG; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR_BIG, 1, abfd) != + SIZEOF_AR_FILE_HDR_BIG)) + return false; + + return true; +} + +static boolean +xcoff_write_archive_contents (abfd) + bfd *abfd; +{ + if (! xcoff_big_format_p (abfd)) + return xcoff_write_archive_contents_old (abfd); + else + return xcoff_write_archive_contents_big (abfd); +} /* We can't use the usual coff_sizeof_headers routine, because AIX always uses an a.out header. */ @@ -1378,7 +2084,7 @@ const bfd_target #else "aixcoff-rs6000", /* name */ #endif - bfd_target_coff_flavour, + bfd_target_coff_flavour, BFD_ENDIAN_BIG, /* data byte order is big */ BFD_ENDIAN_BIG, /* header byte order is big */ diff --git a/bfd/coffcode.h b/bfd/coffcode.h index ca1d522b03..58dd879993 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -1880,17 +1880,23 @@ coff_set_arch_mach_hook (abfd, filehdr) cputype = 0; else { - bfd_byte buf[bfd_coff_symesz (abfd)]; + bfd_byte *buf; struct internal_syment sym; + buf = (bfd_byte *) bfd_malloc (bfd_coff_symesz (abfd)); if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 - || bfd_read (buf, 1, bfd_coff_symesz (abfd), abfd) != bfd_coff_symesz (abfd)) - return false; + || (bfd_read (buf, 1, bfd_coff_symesz (abfd), abfd) + != bfd_coff_symesz (abfd))) + { + bfd_free (buf); + return false; + } coff_swap_sym_in (abfd, (PTR) buf, (PTR) &sym); if (sym.n_sclass == C_FILE) cputype = sym.n_type & 0xff; else cputype = 0; + bfd_free (buf); } } @@ -2762,7 +2768,7 @@ coff_compute_section_file_positions (abfd) current->target_index = target_index++; } - free (section_list); + bfd_free (section_list); } #else /* ! COFF_IMAGE_WITH_PE */ { @@ -3696,7 +3702,7 @@ coff_write_object_contents (abfd) coff_swap_filehdr_out (abfd, (PTR) & internal_f, (PTR) buff); amount = bfd_write ((PTR) buff, 1, bfd_coff_filhsz (abfd), abfd); - free (buff); + bfd_free (buff); if (amount != bfd_coff_filhsz (abfd)) return false; @@ -3716,7 +3722,7 @@ coff_write_object_contents (abfd) coff_swap_aouthdr_out (abfd, (PTR) & internal_a, (PTR) buff); amount = bfd_write ((PTR) buff, 1, bfd_coff_aoutsz (abfd), abfd); - free (buff); + bfd_free (buff); if (amount != bfd_coff_aoutsz (abfd)) return false;